diff options
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | COPYING | 2 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | README | 17 | ||||
-rw-r--r-- | TODO | 9 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | doc/Makefile.am | 5 | ||||
-rw-r--r-- | doc/calcurse.1.txt | 134 | ||||
-rw-r--r-- | doc/manual.txt | 260 | ||||
-rw-r--r-- | doc/submitting-patches.txt | 192 | ||||
-rw-r--r-- | po/POTFILES.in | 2 | ||||
-rw-r--r-- | scripts/Makefile.am | 13 | ||||
-rw-r--r-- | scripts/calcurse-upgrade.sh | 96 | ||||
-rw-r--r-- | src/Makefile.am | 10 | ||||
-rw-r--r-- | src/apoint.c | 712 | ||||
-rw-r--r-- | src/args.c | 1283 | ||||
-rw-r--r-- | src/calcurse.c | 925 | ||||
-rw-r--r-- | src/calcurse.h | 1091 | ||||
-rw-r--r-- | src/calendar.c | 849 | ||||
-rw-r--r-- | src/config.c | 574 | ||||
-rw-r--r-- | src/custom.c | 1920 | ||||
-rw-r--r-- | src/day.c | 1298 | ||||
-rw-r--r-- | src/dmon.c | 184 | ||||
-rw-r--r-- | src/event.c | 179 | ||||
-rw-r--r-- | src/getstring.c | 280 | ||||
-rw-r--r-- | src/help.c | 1173 | ||||
-rw-r--r-- | src/htable.h | 14 | ||||
-rw-r--r-- | src/ical.c | 1090 | ||||
-rw-r--r-- | src/io.c | 3338 | ||||
-rw-r--r-- | src/keys.c | 725 | ||||
-rw-r--r-- | src/llist.c | 211 | ||||
-rw-r--r-- | src/llist.h | 37 | ||||
-rw-r--r-- | src/llist_ts.h | 13 | ||||
-rw-r--r-- | src/mem.c | 271 | ||||
-rw-r--r-- | src/note.c | 235 | ||||
-rw-r--r-- | src/notify.c | 882 | ||||
-rw-r--r-- | src/pcal.c | 291 | ||||
-rw-r--r-- | src/recur.c | 1332 | ||||
-rw-r--r-- | src/sha1.c | 267 | ||||
-rw-r--r-- | src/sha1.h | 57 | ||||
-rw-r--r-- | src/sigs.c | 73 | ||||
-rw-r--r-- | src/todo.c | 497 | ||||
-rw-r--r-- | src/utf8.c | 335 | ||||
-rw-r--r-- | src/utils.c | 1523 | ||||
-rw-r--r-- | src/vars.c | 56 | ||||
-rw-r--r-- | src/wins.c | 878 | ||||
-rw-r--r-- | test/Makefile.am | 31 | ||||
-rw-r--r-- | test/README | 121 | ||||
-rwxr-xr-x | test/appointment-001.sh | 19 | ||||
-rw-r--r-- | test/data/apts | 660 | ||||
-rw-r--r-- | test/data/conf | 75 | ||||
-rw-r--r-- | test/data/todo | 197 | ||||
-rwxr-xr-x | test/day-001.sh | 14 | ||||
-rwxr-xr-x | test/day-002.sh | 39 | ||||
-rwxr-xr-x | test/day-003.sh | 14 | ||||
-rwxr-xr-x | test/next-001.sh | 17 | ||||
-rwxr-xr-x | test/range-001.sh | 19 | ||||
-rwxr-xr-x | test/range-002.sh | 37 | ||||
-rwxr-xr-x | test/range-003.sh | 14 | ||||
-rwxr-xr-x | test/run-test-001.sh | 7 | ||||
-rwxr-xr-x | test/run-test-002.sh | 9 | ||||
-rw-r--r-- | test/run-test.c | 229 | ||||
-rwxr-xr-x | test/search-001.sh | 26 | ||||
-rwxr-xr-x | test/todo-001.sh | 12 | ||||
-rwxr-xr-x | test/todo-002.sh | 10 | ||||
-rwxr-xr-x | test/todo-003.sh | 12 | ||||
-rwxr-xr-x | test/true-001.sh | 3 |
67 files changed, 13937 insertions, 10972 deletions
@@ -5,7 +5,6 @@ Makefile.in Makefile.in.in Makevars aclocal.m4 -config.* configure depcomp install-sh @@ -15,6 +14,8 @@ stamp-h1 autom4te.cache/ m4/ +./config.* + doc/*.1 doc/*.html doc/*.pdf @@ -31,3 +32,6 @@ po/stamp-po src/*.o src/.deps/ src/calcurse + +test/*.o +test/run-test @@ -1,4 +1,4 @@ -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 diff --git a/Makefile.am b/Makefile.am index 5dd1ed9..8e7e1b0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS= foreign ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = po src +SUBDIRS = po src test scripts if ENABLE_DOCS SUBDIRS += doc @@ -6,20 +6,25 @@ Read `INSTALL` for instructions on how to build and install calcurse. Check `TODO` for things that still need to be done. Browse the file `doc/manual.html` (or its source `doc/manual.txt`) for -narrative descriptions on how to use calcurse. +detailed descriptions on how to use calcurse. Package Overview ---------------- -You should be reading this file in a directory called: `calcurse-x.x`, where -`x.x` is the current version number. There should be two subdirectories : `src` -and `doc`. Detailed documentation in HTML format can be found in the `doc` -directory. Calcurse sources can be found in the `src` directory. +You should be reading this file in a directory called: `calcurse-x.y.z`, where +`x.y.z` is the current version number. + +There should be four subdirectories: + +* `src`: contains calcurse sources +* `test`: contains a test suite and test cases for calcurse +* `scripts`: contains additional scripts, such as `calcurse-upgrade` +* `doc`: contains detailed documentation in plain text and HTML Authors ------- -* Frederic Culot (Founder, Lead Developer) +* Frederic Culot (Founder) * Lukas Fleischer (Developer) Contributors @@ -3,20 +3,15 @@ calcurse TODO list Here is a list of modifications we will perform on calcurse in future releases. They are grouped into three different priority categories. Feel free to send us -an email (misc@calcurse.org or bugs@calcurse.org) if you would like to see a -feature added in calcurse which does not appear in this list. +an email (misc@calcurse.org) if you would like to see a feature added in +calcurse which does not appear in this list. High ---- -* Add support for UTF-8 -* Implement the send-item functionality to export a single item and pipe it to - an external process * Add a key binding to toggle between visible/hidden tasks inside todo panel * Add an optional argument to the --next flag to check for next appointment starting from the specified time -* Improve the way one can specify a duration (allowing something like - XXdXXhXXmXXs) * Implement word-wrap in the sidebar * Support additional iCalendar keywords in appointment/event/todo notes (see http://lists.calcurse.org/misc/msg00017.html) diff --git a/configure.ac b/configure.ac index debd8b8..33b72ca 100644 --- a/configure.ac +++ b/configure.ac @@ -145,7 +145,8 @@ AM_XGETTEXT_OPTION([--no-location --keyword=_ --keyword=N_]) #------------------------------------------------------------------------------- # Create Makefiles #------------------------------------------------------------------------------- -AC_OUTPUT(Makefile doc/Makefile src/Makefile po/Makefile.in po/Makefile) +AC_OUTPUT(Makefile doc/Makefile src/Makefile test/Makefile scripts/Makefile \ + po/Makefile.in po/Makefile) #------------------------------------------------------------------------------- # Summary #------------------------------------------------------------------------------- diff --git a/doc/Makefile.am b/doc/Makefile.am index caa90d2..5888b18 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -14,17 +14,20 @@ A2X_ARGS = \ endif dist_doc_DATA = \ - manual.html + manual.html \ + submitting-patches.html dist_man_MANS = \ calcurse.1 EXTRA_DIST = \ manual.txt \ + submitting-patches.txt \ calcurse.1.txt CLEANFILES = \ manual.html \ + submitting-patches.html \ calcurse.1 docdir = $(datadir)/doc/$(PACKAGE) diff --git a/doc/calcurse.1.txt b/doc/calcurse.1.txt index 884aa34..6768088 100644 --- a/doc/calcurse.1.txt +++ b/doc/calcurse.1.txt @@ -1,6 +1,6 @@ //// /* - * 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 @@ -42,7 +42,7 @@ Synopsis -------- [verse] -*calcurse* [*-h*|*-v*] [*-N*] [*-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*] @@ -103,6 +103,32 @@ appointments can be specified using the *-c* flag. Specify the data directory to use. This option is incompatible with -c. If not specified, the default directory is *~/.calcurse/*. +*--format-apt* <format>:: + Specify a format to control the output of appointments in non-interactive + mode. See the 'FORMAT STRINGS' section for detailed information on format + strings. + +*--format-recur-apt* <format>:: + Specify a format to control the output of recurrent appointments in + non-interactive mode. See the 'FORMAT STRINGS' section for detailed + information on format strings. + +*--format-event* <format>:: + Specify a format to control the output of events in non-interactive mode. See + the 'FORMAT STRINGS' section for detailed information on format strings. + +*--format-recur-event* <format>:: + Specify a format to control the output of recurrent events in non-interactive + mode. See the 'FORMAT STRINGS' section for detailed information on format + strings. + +*--format-todo* <format>:: + Specify a format to control the output of todo items in non-interactive mode. + See the 'FORMAT STRINGS' section for detailed information on format strings. + +*-g*, *--gc*:: + Run the garbage collector for note files and exit. + *-h*, *--help*:: Print a short help text describing the supported command-line options, and exit. @@ -117,14 +143,16 @@ appointments can be specified using the *-c* flag. 'Note:' the calendar from which to read the appointments can be specified using the *-c* flag. -*-N*, *--note*:: - When used with the *-a* or *-t* flag, also print note content if one is - associated with the displayed item. - *-r*[num], *--range*[=num]:: Print events and appointments for the 'num' number of days and exit. If no 'num' is given, a range of 1 day is considered. +*--read-only*:: + Don't save configuration nor appointments/todos. ++ +'Warning:' Use this this with care! If you run an interactive calcurse instance +in read-only mode, all changes from this session will be lost without warning! + *-s*[date], *--startday*[=date]:: Print events and appointments from 'date' and exit. If no 'date' is given, the current day is considered. @@ -161,6 +189,98 @@ such as: $ calcurse --export > my_data.dat ---- +'Note:' The *-N* option has been removed in calcurse 3.0.0. See the 'FORMAT +STRINGS' section on how to print note along with appointments and events. + +Format strings +-------------- + +Format strings are composed of printf()-style format specifiers -- ordinary +characters are copied to stdout without modification. Each specifier is +introduced by a *%* and is followed by a character which specifies the field to +print. The set of available fields depends on the item type. + +Format specifiers for appointments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*s*:: + Print the start time of the appointment as UNIX time stamp +*S*:: + Print the start time of the appointment using the *hh:mm* format +*d*:: + Print the duration of the appointment in seconds +*e*:: + Print the end time of the appointment as UNIX time stamp +*E*:: + Print the end time of the appointment using the *hh:mm* format +*m*:: + Print the description of the item +*n*:: + Print the name of the note file belonging to the item +*N*:: + Print the note belonging to the item + +Format specifiers for events +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*m*:: + Print the description of the item +*n*:: + Print the name of the note file belonging to the item +*N*:: + Print the note belonging to the item + +Format specifiers for todo items +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*p*:: + Print the priority of the item +*m*:: + Print the description of the item +*n*:: + Print the name of the note file belonging to the item +*N*:: + Print the note belonging to the item + +Examples +~~~~~~~~ + +*`calcurse -r7 --format-apt='- %S -> %E\n\t%m\n%N'`*:: + Print appointments and events for the next seven days. Also, print the notes + attached to each regular appointment (simulates *-N* for appointments). + +*`calcurse -r7 --format-apt=' - %m (%S to %E)\n' --format-recur-apt=' - %m (%S to %E)\n'`*:: + Print appointments and events for the next seven days and use a custom format + for (recurrent) appointments: * - Some appointment (18:30 to 21:30)*. + +*`calcurse -t --format-todo '(%p) %m\n'`*:: + List all todo items and put parentheses around the priority specifiers. + +Extended format specifiers +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Extended format specifiers can be used if you want to specify advanced +formatting options. Extended specifiers are introduced by *%(* and are +terminated by a closing parenthesis (*)*). The following list includes all +short specifiers and corresponding long options: + +* *s*: *(start)* +* *S*: *(start:epoch)* +* *d*: *(duration)* +* *e*: *(end)* +* *E*: *(end:epoch)* +* *m*: *(message)* +* *n*: *(noteid)* +* *N*: *(note)* +* *p*: *(priority)* + +The *(start)* and *(end)* specifiers support strftime()-style extended +formatting options that can be used for fine-grained formatting. Additionally, +the special formats *epoch* (which is equivalent to *(start:%s)* or *(end:%s)*) +and *default* (which is mostly equivalent to *(start:%H:%M)* or *(end:%H:%M)* +but displays *..:..* if the item doesn't start/end at the current day) are +supported. + Notes ----- @@ -271,5 +391,5 @@ Authors Copyright --------- -Copyright (c) 2004-2011 calcurse Development Team. +Copyright (c) 2004-2012 calcurse Development Team. This software is released under the BSD License. diff --git a/doc/manual.txt b/doc/manual.txt index c0a992d..80993cf 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -1,6 +1,6 @@ //// /* - * 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 @@ -36,7 +36,7 @@ CALCURSE - text-based organizer Abstract -------- -This manual describes `calcurse` functionnalities, and how to use them. The +This manual describes `calcurse` functionalities, and how to use them. The installation from source is first described, together with the available command line arguments. The user interface is then presented, with all of the customizable options that change `calcurse` behavior. Last, bug reporting @@ -113,8 +113,7 @@ library already installed on your computer, but if not, you can find it at the following url: http://ftp.gnu.org/pub/gnu/ncurses/ NOTE: It is also possible to link `calcurse` against the `ncursesw` library - (ncurses with support for unicode). However, UTF-8 is not yet supported - by `calcurse`. + (ncurses with support for unicode). [[install_requirements_gettext]] gettext library @@ -201,7 +200,7 @@ days will be returned. As an example, typing `calcurse -d 3` will display your appointments for today, tomorrow, and the day after tomorrow. Possible formats for specifying the date are defined inside the general configuration menu (see <<options_general,General options>>), using the -`input_datefmt` variable. +`format.inputdate` variable. + Note: as for the `-a` flag, the calendar from which to read the appointments can be specified using the `-c` flag. @@ -210,6 +209,34 @@ can be specified using the `-c` flag. Specify the data directory to use. This option is incompatible with -c. If not specified, the default directory is `~/.calcurse/`. +`--format-apt <format>`:: + Specify a format to control the output of appointments in non-interactive + mode. See the <<basics_format_strings,Format strings>> section for detailed + information on format strings. + +`--format-recur-apt <format>`:: + Specify a format to control the output of recurrent appointments in + non-interactive mode. See the <<basics_format_strings,Format strings>> + section for detailed information on format strings. + +`--format-event <format>`:: + Specify a format to control the output of events in non-interactive mode. See + the <<basics_format_strings,Format strings>> section for detailed information + on format strings. + +`--format-recur-event <format>`:: + Specify a format to control the output of recurrent events in non-interactive + mode. See the <<basics_format_strings,Format strings>> section for detailed + information on format strings. + +`--format-todo <format>`:: + Specify a format to control the output of todo items in non-interactive mode. + See the <<basics_format_strings,Format strings>> section for detailed + information on format strings. + +`-g, --gc`:: + Run the garbage collector for note files and exit. + `-h, --help`:: Print a short help text describing the supported command-line options, and exit. @@ -224,14 +251,16 @@ can be specified using the `-c` flag. Note: the calendar from which to read the appointments can be specified using the `-c` flag. -`-N, --note`:: - When used with the `-a` or `-t` flag, also print note content if one is - associated with the displayed item. - `-r[num], --range[=num]`:: Print events and appointments for the num number of days and exit. If no num is given, a range of 1 day is considered. +`--read-only`:: + Don't save configuration nor appointments/todos. ++ +WARNING: Use this this with care! If you run an interactive calcurse instance +in read-only mode, all changes from this session will be lost without warning! + `-s[date], --startday[=date]`:: Print events and appointments from date and exit. If no date is given, the current day is considered. @@ -268,6 +297,100 @@ such as: $ calcurse --export > my_data.dat ---- +NOTE: The `-N` option has been removed in calcurse 3.0.0. See the +<<basics_format_strings,Format strings>> section on how to print note along +with appointments and events. + +[[basics_format_strings]] +Format strings +^^^^^^^^^^^^^^ + +Format strings are composed of printf()-style format specifiers -- ordinary +characters are copied to stdout without modification. Each specifier is +introduced by a `%` and is followed by a character which specifies the field to +print. The set of available fields depends on the item type. + +Format specifiers for appointments +++++++++++++++++++++++++++++++++++ + +`s`:: + Print the start time of the appointment as UNIX time stamp +`S`:: + Print the start time of the appointment using the `hh:mm` format +`d`:: + Print the duration of the appointment in seconds +`e`:: + Print the end time of the appointment as UNIX time stamp +`E`:: + Print the end time of the appointment using the `hh:mm` format +`m`:: + Print the description of the item +`n`:: + Print the name of the note file belonging to the item +`N`:: + Print the note belonging to the item + +Format specifiers for events +++++++++++++++++++++++++++++ + +`m`:: + Print the description of the item +`n`:: + Print the name of the note file belonging to the item +`N`:: + Print the note belonging to the item + +Format specifiers for todo items +++++++++++++++++++++++++++++++++ + +`p`:: + Print the priority of the item +`m`:: + Print the description of the item +`n`:: + Print the name of the note file belonging to the item +`N`:: + Print the note belonging to the item + +Examples +++++++++ + +`calcurse -r7 --format-apt='- %S -> %E\n\t%m\n%N'`:: + Print appointments and events for the next seven days. Also, print the notes + attached to each regular appointment (simulates `-N` for appointments). + +`calcurse -r7 --format-apt=' - %m (%S to %E)\n' --format-recur-apt=' - %m (%S to %E)\n'`:: + Print appointments and events for the next seven days and use a custom format + for (recurrent) appointments: ` - Some appointment (18:30 to 21:30)`. + +`calcurse -t --format-todo '(%p) %m\n'`:: + List all todo items and put parentheses around the priority specifiers. + +Extended format specifiers +++++++++++++++++++++++++++ + +Extended format specifiers can be used if you want to specify advanced +formatting options. Extended specifiers are introduced by `%(` and are +terminated by a closing parenthesis (`)`). The following list includes all +short specifiers and corresponding long options: + +* `s`: `(start)` +* `S`: `(start:epoch)` +* `d`: `(duration)` +* `e`: `(end)` +* `E`: `(end:epoch)` +* `m`: `(message)` +* `n`: `(noteid)` +* `N`: `(note)` +* `p`: `(priority)` + +The `(start)` and `(end)` specifiers support strftime()-style extended +formatting options that can be used for fine-grained formatting. Additionally, +the special formats `epoch` (which is equivalent to `(start:%s)` or `(end:%s)`) +and `default` (which is mostly equivalent to `(start:%H:%M)` or `(end:%H:%M)` +but displays `..:..` if the item doesn't start/end at the current day) are +supported. + [[basics_invocation_variable]] Environment variable for i18n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -492,11 +615,11 @@ for upcoming appointments and runs the user-defined notification command when necessary. When the user interface is started again, the daemon automatically stops. -`calcurse` background activity can be logged (set the `notify-daemon_log` -variable in the notification configuration <<options_notify,menu>>), -and in that case, information about the daemon start and stop time, reminders' -command launch time, signals received... will be written in the `daemon.log` -file (see section <<basics_files,files>>). +`calcurse` background activity can be logged (set the `daemon.log` variable in +the notification configuration <<options_notify,menu>>), and in that case, +information about the daemon start and stop time, reminders' command launch +time, signals received... will be written in the `daemon.log` file (see section +<<basics_files,files>>). Using the `--status` command line option (see section <<basics_invocation_commandline,Command line arguments>>), one can know if @@ -530,9 +653,10 @@ $HOME/.calcurse/ ---- `notes/`:: this subdirectory contains descriptions of the notes which are attached to - appointments, events or todos. One text file is created per note, whose name - is built using mkstemp(3) and should be unique, but with no relation with the - corresponding item's description. + appointments, events or todos. Since the file name of each note file is a + SHA1 hash of the note itself, multiple items can share the same note file. + calcurse provides a garbage collector (see the `-g` command line parameter) + that can be used to remove note files which are no longer linked to any item. `conf`:: this file contains the user configuration `keys`:: @@ -618,55 +742,57 @@ General options These options control `calcurse` general behavior, as described below: -`auto_save` (default: *yes*):: +`general.autosave` (default: *yes*):: This option allows to automatically save the user's data (if set to *yes*) when quitting. <p class="rq"><span class="valorise">warning:</span> No data - will be automatically saved if `auto_save` is set to *no*. This means the - user must press `S` (for saving) in order to retrieve its modifications. + will be automatically saved if `general.autosave` is set to *no*. This means + the user must press `S` (for saving) in order to retrieve its modifications. -`periodic_save` (default: *0*):: +`general.autogc` (default: *no*):: + Automatically run the garbage collector for note files when quitting. + +`general.periodicsave` (default: *0*):: If different from `0`, user's data will be automatically saved every - *periodic_save* minutes. When an automatic save is performed, two asterisks - (i.e. `**`) will appear on the top right-hand side of the screen). + *general.periodicsave* minutes. When an automatic save is performed, two + asterisks (i.e. `**`) will appear on the top right-hand side of the screen). -`confirm_quit` (default: *yes*):: +`general.confirmquit` (default: *yes*):: If set to *yes*, confirmation is required before quitting, otherwise pressing `Q` will cause `calcurse` to quit without prompting for user confirmation. -`confirm_delete` (default: *yes*):: +`general.confirmdelete` (default: *yes*):: If this option is set to *yes*, pressing `D` for deleting an item (either a *todo*, *appointment*, or *event*), will lead to a prompt asking for user confirmation before removing the selected item from the list. Otherwise, no confirmation will be needed before deleting the item. -`skip_system_dialogs` (default: *no*):: - Setting this option to *yes* will result in skipping the system dialogs +`general.systemdialogs` (default: *yes*):: + Setting this option to *no* will result in skipping the system dialogs related to the saving and loading of data. This can be useful to speed up the input/output processes. -`skip_progress_bar` (default: *no*):: - If set to *yes*, this will cause the disappearing of the progress bar which - is usually shown when saving data to file. If set to *no*, this bar will be +`general.progressbar` (default: *yes*):: + If set to *no*, this will cause the disappearing of the progress bar which is + usually shown when saving data to file. If set to *yes*, this bar will be displayed, together with the name of the file being saved (see section <<basics_files,calcurse files>>). -`calendar_default_view` (default: *0*):: +`appearance.calendarview` (default: *0*):: If set to `0`, the monthly calendar view will be displayed by default otherwise it is the weekly view that will be displayed. -`week_begins_on_monday` (default: *yes*):: - One can choose between Monday and Sunday as the first day of the week. If the - option `week_begins_on_monday` is set to *yes*, Monday will be first in the - calendar view. Else if the option is set to *no*, then Sunday will be the - first day of the week. +`general.firstdayofweek` (default: *monday*):: + One can choose between Monday and Sunday as the first day of the week. If + `general.firstdayofweek` is set to *monday*, Monday will be first in the + calendar view. Otherwise, Sunday will be the first day of the week. -`output_datefmt` (default: *%D*):: +`format.outputdate` (default: *%D*):: This option indicates the format to be used when displaying dates in non-interactive mode. Using the default values, dates are displayed the following way: *mm/dd/aa*. You can see all of the possible formats by typing `man 3 strftime` inside a terminal. -`input_datefmt` (default: *1*):: +`format.inputdate` (default: *1*):: This option indicates the format that will be used to enter dates in *calcurse*. Four choices are available: + @@ -679,12 +805,12 @@ These options control `calcurse` general behavior, as described below: Key bindings ~~~~~~~~~~~~ -One can define it's own keybindings within the `Keys` configuration menu. The +One can define ones own key bindings within the `Keys` configuration menu. The default keys look like the one used by the `vim` editor, especially the displacement keys. Anyway, within this configuration menu, users can redefine all of the keys available from within calcurse's user interface. -To define new keybindings, first highlight the action to which it will apply. +To define new key bindings, first highlight the action to which it will apply. Then, delete the actual key binding if necessary, and add a new one. You will then be asked to press the key corresponding to the new binding. It is possible to define more than one key binding for a single action. @@ -710,6 +836,10 @@ While inside the key configuration menu, an online help is available for each one of the available actions. This help briefly describes what the highlighted action is used for. +NOTE: As of calcurse 3.0.0, displacement commands can be preceded by an + optional number to repeat the command. For example, `10k` will move the + cursor ten weeks forwards if you use default key bindings. + Color themes ~~~~~~~~~~~~ @@ -726,7 +856,7 @@ bar. A black and white theme is also available, in order to support non-color terminals. NOTE: Depending on your terminal type and on the value of the `$TERM` - environnement variable, color could or could not be supported. An error + environment variable, color could or could not be supported. An error message will appear if you try to change colors whereas your terminal does not support this feature. If you do know your terminal supports colors but could not get `calcurse` to display them, try to set your @@ -740,13 +870,13 @@ The default layout makes the calendar panel to be displayed on the top-right corner of the terminal, the todo panel on the bottom-right corner, while the appointment panel is displayed on the left hand-side of the screen (see the figure in section <<basics_interface_interactive,Interactive mode>> for an -exemple of the default layout). By choosing another layout in the -configuration screen, user can customize `calcurse` appearence to best suit his +example of the default layout). By choosing another layout in the +configuration screen, user can customize `calcurse` appearance to best suit his needs by placing the different panels where needed. The following option is used to modify the layout configuration: -`layout` (default: *0*):: +`appearance.layout` (default: *0*):: Eight different layouts are to be chosen from (see layout configuration screen for the description of the available layouts). @@ -759,7 +889,7 @@ list. The following option is used to change the width of the sidebar: -`side-bar_width` (default: *0*):: +`appearance.sidebarwidth` (default: *0*):: Width (in percentage, 0 being the minimum width) of the side bar. [[options_notify]] @@ -768,27 +898,27 @@ Notify-bar settings The following options are used to modify the notify-bar behavior: -`notify-bar_show` (default: *yes*):: +`appearance.notifybar` (default: *yes*):: This option indicates if you want the notify-bar to be displayed or not. -`notify-bar_date` (default: *%a %F*):: +`format.notifydate` (default: *%a %F*):: With this option, you can specify the format to be used to display the current date inside the notification bar. You can see all of the possible formats by typing `man 3 strftime` inside a terminal. -`notify-bar_time` (default: *%T*):: +`format.notifytime` (default: *%T*):: With this option, you can specify the format to be used to display the current time inside the notification bar. You can see all of the possible formats by typing `man 3 strftime` inside a terminal. -`notify-bar_warning` (default: *300*):: +`notification.warning` (default: *300*):: When there is an appointment which is flagged as `important` within the next - `notify-bar_warning` seconds, the display of that appointment inside the - notify-bar starts to blink. Moreover, the command defined by the - `notify-bar_command` option will be launched. That way, the user is warned + `notification.warning` seconds, the display of that appointment inside the + notify-bar starts to blink. Moreover, the command defined by the + `notification.command` option will be launched. That way, the user is warned and knows there will be soon an upcoming appointment. -`notify-bar_command` (default: *printf '\a'*):: +`notification.command` (default: *printf '\a'*):: This option indicates which command is to be launched when there is an upcoming appointment flagged as `important`. This command will be passed to the user's shell which will interpret it. To know what shell must be used, @@ -805,13 +935,17 @@ $ calcurse --next | mail -s "[calcurse] upcoming appointment!" user@host.com ---- ==== -`notify-daemon_enable` (default: *no*):: +`notification.notifyall` (default: *no*):: + Invert the sense of flagging an appointment as `important`. If this is + enabled, all appointments will be notified - except for flagged ones. + +`daemon.enable` (default: *no*):: If set to yes, daemon mode will be enabled, meaning `calcurse` will run into background when the user's interface is exited. This will allow the notifications to be launched even when the interface is not running. More details can be found in section <<basics_daemon,Background mode>>. -`notify-daemon_log` (default: *no*):: +`daemon.log` (default: *no*):: If set to yes, `calcurse` daemon activity will be logged (see section <<basics_files,files>>). @@ -825,9 +959,9 @@ be used instead of *xterm-color* to set the `$TERM` variable: ____ "The xterm-color value for $TERM is a bad choice for XFree86 xterm because it -is commonly used for a terminfo entry which happens to not support bce. Use the -xterm-xfree86 entry which is distributed with XFree86 xterm (or the similar one -distributed with ncurses)." +is commonly used for a `terminfo` entry which happens to not support bce. Use +the xterm-xfree86 entry which is distributed with XFree86 xterm (or the similar +one distributed with ncurses)." ____ [[bugs]] @@ -878,7 +1012,7 @@ http://www.gnu.org/software/gettext/manual/ IMPORTANT: Since we switched to Transifex, editing *po* files is not necessary anymore as Transifex provides a user-friendly, intuitive web - interface for translators. Knowlegde of `gettext` and the *po* + interface for translators. Knowledge of `gettext` and the *po* format is still useful for those of you who prefer the command line and local editing. If you want to use the web UI to edit the translation strings, you can skip over to <<transifex_webui,Using @@ -906,12 +1040,12 @@ translation. So, translatable strings are first marked by the coders within the `C` source files, then gathered in a template file (*calcurse.pot* - the *pot* extension meaning *portable object template*). The content of this template file is then -merged with the translation files for each language (*fr.po* for french, for +merged with the translation files for each language (*fr.po* for French, for instance - with *po* standing for *portable object*, ie meant to be read and edited by humans). A given translation team will take this file, translate its strings, and send it back to the developers. At compilation time, a binary version of this file (for efficiency reasons) will be produced (*fr.mo* - *mo* -stands for *machine object*, ie meant to be read by programs), and then +stands for *machine object*, i.e. meant to be read by programs), and then installed. Then `calcurse` will use this file at runtime, translating the strings according to the locale settings of the user. @@ -1050,7 +1184,7 @@ Using transifex-client You can also use a command line client to submit translations instead of having to use the web interface every time you want to submit an updated version. If -you have a recent version of setuptools installed, you can get the CLI client +you have a recent version of `setuptools` installed, you can get the CLI client by issuing the following command: ---- @@ -1074,7 +1208,7 @@ To submit changes back to the server, use: $ tx push -r calcurse.calcursepot -t -l <locale> ---- -For more details, read up on transifex-client usage at the +For more details, read up on `transifex-client` usage at the http://help.transifex.net/user-guide/client/[The Transifex Command-line Client v0.4] section of the http://help.transifex.net/[Transifex documentation]. diff --git a/doc/submitting-patches.txt b/doc/submitting-patches.txt new file mode 100644 index 0000000..0b20fad --- /dev/null +++ b/doc/submitting-patches.txt @@ -0,0 +1,192 @@ +//// +/* + * 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. + */ +//// + +CALCURSE - Submitting Patches +============================= + +This is a short summary of guidelines you should try to follow when submitting +patches to calcurse. + +Fetching the most recent source +------------------------------- + +The whole source code currently is under version control using Git as VCS. You +can retrieve a local copy of the development tree using: + +---- +$ git clone git://git.calcurse.org/calcurse.git +---- + +This will create a new directory `calcurse` that contains the cloned +repository. + +If you want to follow the maintenance branch (`maint`) as well (e.g. to create +a bug fix), setting up a tracking branch is recommended: + +---- +$ git branch -t maint origin/maint +---- + +Creating a working branch +------------------------- + +Whenever you want to work on a new feature, do it in a separate branch. Having +diverging commits in the `master` branch might cause conflicts when pulling in +new changes. Thus, creating a new development branch *before* doing any changes +is good practice. And even before doing that, you should update the master +branch of your working copy: + +---- +$ git checkout master +$ git pull origin master +$ git checkout -b wip +---- + +You can replace `wip` by any name you like. + +Maintenance patches such as bug fixes and stability improvements should be +based on the `maint` branch instead: + +---- +$ git checkout maint +$ git pull origin maint +$ git checkout -b wip-maint +---- + +Committing the changes +---------------------- + +Edit files in the source tree and test your changes. When everything seems to +be fine, you're ready to commit to your local working tree: + +---- +$ git commit -as +---- + +If you added or removed files, you probably need to run `git add` or `git rm` +before committing so that Git is aware of them. + +If you work on more than a small bug fix, you should split your work into +several commits. Try to keep your commits small and focused. Smaller patches +are way easier to review and have a better chance of being included in mainline +development. + +Also try to make your commit messages brief and descriptive. The first line of +the commit message should be a short description (not more than 50 characters) +and should use imperative, present tense. If there are details that cannot be +expressed in these size constraints, put them in separate text paragraphs +separated by blank lines and wrapped to 72 columns. If you use Vim, +`gitcommit.vim` will do most of the job for you. + +Here's a sample commit message: + +---- +Invoke vars_init() before importing data with "-i" + +We forgot to call vars_init() when importing an item using the "-i" +command line argument, which led to the pager configuration variable +being unset and hence the pager invocation (triggered to show the log in +case there are any errors during import) failing. + +Fix this by calling vars_init() before io_import_data(). + +Reported-by: Andraž 'ruskie' Levstik <ruskie@codemages.net> +Signed-off-by: Lukas Fleischer <calcurse@cryptocrack.de> +---- + +The `-s` in the `git commit` invocation makes Git add a "Signed-off-by" line to +credit yourself and to confirm that your contribution was created in whole or +in part by you and you have the right to submit it under the BSD license. +Please do not remove that line when editing the commit message. + +Creating a patch series +----------------------- + +As soon as you finished all your work, test everything again and create a patch +series: + +---- +$ git format-patch master +---- + +Replace `master` by `maint` if your development branch is based on the +maintenance branch: + +---- +$ git format-patch maint +---- + +Submitting patches +------------------ + +Send your patch series to one of the mailing lists: + +---- +$ git send-email *.patch +---- + +The `bugs` mailing list should be used for bug fixes, `misc` should be used for +everything else. + +You can also add a cover letter and/or add annotations to patches: + +---- +$ git send-email --cover-letter --annotate *.patch +---- + +Additional information on the particular patches, which shouldn't appear in the +commit message itself, can be added immediately after the `---`. + +Importing patches +----------------- + +Git also provides a tool for importing a patch series submitted via `git +send-email`. Just save all mails that contain patches into mbox files and use +`git am` to apply them to your working branch: + +---- +$ git am <mbox>... +---- + +If you use mutt, you can also add following macro to apply the patch contained +in the current mail to your local Git repository by pressing `A`: + +---- +set mbox_type=mbox +set my_git_repo_path=$HOME/src/calcurse + +macro index,pager A "<pipe-message>(cd $my_git_repo_path && git am)<enter>" +---- + +To setup different Git repositories per mailing list (in case you follow several +different development lists), simply bind the macro to a `folder-hook` or to a +`message-hook` and use different repository paths per hook. diff --git a/po/POTFILES.in b/po/POTFILES.in index 6c588c5..62b460b 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -16,3 +16,5 @@ src/utils.c src/vars.c src/wins.c src/dmon.c + +scripts/calcurse-upgrade.sh diff --git a/scripts/Makefile.am b/scripts/Makefile.am new file mode 100644 index 0000000..5502cfd --- /dev/null +++ b/scripts/Makefile.am @@ -0,0 +1,13 @@ +AUTOMAKE_OPTIONS = foreign + +dist_bin_SCRIPTS = \ + calcurse-upgrade + +EXTRA_DIST = \ + calcurse-upgrade.sh + +CLEANFILES = \ + calcurse-upgrade + +calcurse-upgrade: calcurse-upgrade.sh + $(AM_V_GEN) $(INSTALL) $< $@ diff --git a/scripts/calcurse-upgrade.sh b/scripts/calcurse-upgrade.sh new file mode 100644 index 0000000..ffe110a --- /dev/null +++ b/scripts/calcurse-upgrade.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +export TEXTDOMAIN='calcurse' + +set -e + +if [ "$1" = "--config" ]; then + CONFFILE=$2 +else + CONFFILE=$HOME/.calcurse/conf +fi + +if [ ! -e "$CONFFILE" ]; then + echo "$(gettext "Configuration file not found:") $CONFFILE" >&2 + exit 1 +fi + +if grep -q -e '^auto_save=' -e '^auto_gc=' -e '^periodic_save=' \ + -e '^confirm_quit=' -e '^confirm_delete=' -e '^skip_system_dialogs=' \ + -e '^skip_progress_bar=' -e '^calendar_default_view=' \ + -e '^week_begins_on_monday=' -e '^color-theme=' -e '^layout=' \ + -e '^side-bar_width=' -e '^notify-bar_show=' -e '^notify-bar_date=' \ + -e '^notify-bar_clock=' -e '^notify-bar_warning=' -e '^notify-bar_command=' \ + -e '^notify-all=' -e '^output_datefmt=' -e '^input_datefmt=' \ + -e '^notify-daemon_enable=' -e '^notify-daemon_log=' "$CONFFILE"; then + + echo "$(gettext "Pre-3.0.0 configuration file format detected...")" + + tmpfile="${TMPDIR:-/tmp}/calcurse-upgrade.$!" + [ -e "$tmpfile" ] && exit 1 + + echo -n "$(gettext "Upgrade configuration directives...")" + + sed -e 's/^auto_save=/general.autosave=/' \ + -e 's/^auto_gc=/general.autogc=/' \ + -e 's/^periodic_save=/general.periodicsave=/' \ + -e 's/^confirm_quit=/general.confirmquit=/' \ + -e 's/^confirm_delete=/general.confirmdelete=/' \ + -e 's/^skip_system_dialogs=/general.systemdialogs=/' \ + -e 's/^skip_progress_bar=/general.progressbar=/' \ + -e 's/^calendar_default_view=/appearance.calendarview=/' \ + -e 's/^week_begins_on_monday=/general.firstdayofweek=/' \ + -e 's/^color-theme=/appearance.theme=/' \ + -e 's/^layout=/appearance.layout=/' \ + -e 's/^side-bar_width=/appearance.sidebarwidth=/' \ + -e 's/^notify-bar_show=/appearance.notifybar=/' \ + -e 's/^notify-bar_date=/format.notifydate=/' \ + -e 's/^notify-bar_clock=/format.notifytime=/' \ + -e 's/^notify-bar_warning=/notification.warning=/' \ + -e 's/^notify-bar_command=/notification.command=/' \ + -e 's/^notify-all=/notification.notifyall=/' \ + -e 's/^output_datefmt=/format.outputdate=/' \ + -e 's/^input_datefmt=/format.inputdate=/' \ + -e 's/^notify-daemon_enable=/daemon.enable=/' \ + -e 's/^notify-daemon_log=/daemon.log=/' "$CONFFILE" > "$tmpfile" + mv "$tmpfile" "$CONFFILE" + + if grep -q -e '^[^#=][^#=]*$' -e '^[^#=][^#=]*#.*$' "$CONFFILE"; then + sed -e '/^general.autosave=/{N;s/\n//}' \ + -e '/^general.autogc=/{N;s/\n//}' \ + -e '/^general.periodicsave=/{N;s/\n//}' \ + -e '/^general.confirmquit=/{N;s/\n//}' \ + -e '/^general.confirmdelete=/{N;s/\n//}' \ + -e '/^general.systemdialogs=/{N;s/\n//}' \ + -e '/^general.progressbar=/{N;s/\n//}' \ + -e '/^appearance.calendarview=/{N;s/\n//}' \ + -e '/^general.firstdayofweek=/{N;s/\n//}' \ + -e '/^appearance.theme=/{N;s/\n//}' \ + -e '/^appearance.layout=/{N;s/\n//}' \ + -e '/^appearance.sidebarwidth=/{N;s/\n//}' \ + -e '/^appearance.notifybar=/{N;s/\n//}' \ + -e '/^format.notifydate=/{N;s/\n//}' \ + -e '/^format.notifytime=/{N;s/\n//}' \ + -e '/^notification.warning=/{N;s/\n//}' \ + -e '/^notification.command=/{N;s/\n//}' \ + -e '/^notification.notifyall=/{N;s/\n//}' \ + -e '/^format.outputdate=/{N;s/\n//}' \ + -e '/^format.inputdate=/{N;s/\n//}' \ + -e '/^daemon.enable=/{N;s/\n//}' \ + -e '/^daemon.log=/{N;s/\n//}' "$CONFFILE" > "$tmpfile" + mv "$tmpfile" "$CONFFILE" + fi + + awk ' + BEGIN { FS=OFS="=" } + $1 == "general.systemdialogs" || $1 == "general.progressbar" \ + { $2 = ($2 == "yes") ? "no" : "yes" } + $1 == "general.firstdayofweek" { $2 = ($2 == "yes") ? "monday" : "sunday" } + { print } + ' < "$CONFFILE" > "$tmpfile" + mv "$tmpfile" "$CONFFILE" + + echo -n ' ' + echo "$(gettext 'done')" +fi + diff --git a/src/Makefile.am b/src/Makefile.am index faacf46..7eab77f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,26 +2,36 @@ AUTOMAKE_OPTIONS = foreign bin_PROGRAMS = calcurse +AM_CFLAGS = -std=c99 -pedantic -D_POSIX_C_SOURCE=200809L + calcurse_SOURCES = \ calcurse.c \ calcurse.h \ htable.h \ llist.h \ llist_ts.h \ + sha1.h \ apoint.c \ args.c \ calendar.c \ + config.c \ custom.c \ day.c \ event.c \ + getstring.c \ help.c \ + ical.c \ io.c \ keys.c \ llist.c \ + note.c \ notify.c \ + pcal.c \ recur.c \ + sha1.c \ sigs.c \ todo.c \ + utf8.c \ utils.c \ vars.c \ wins.c \ diff --git a/src/apoint.c b/src/apoint.c index 6fd9e64..1483beb 100644 --- a/src/apoint.c +++ b/src/apoint.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -41,46 +41,41 @@ #include "calcurse.h" -llist_ts_t alist_p; -static struct apoint bkp_cut_apoint; -static int hilt; +llist_ts_t alist_p; +static struct apoint bkp_cut_apoint; +static int hilt; -void -apoint_free_bkp (enum eraseflg flag) +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, flag); + 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) +static void apoint_free(struct apoint *apt) { - mem_free (apt->mesg); - erase_note (&apt->note, ERASE_FORCE_KEEP_NOTE); - mem_free (apt); + mem_free(apt->mesg); + erase_note(&apt->note); + mem_free(apt); } -static void -apoint_dup (struct apoint *in, struct apoint *bkp) +static void apoint_dup(struct apoint *in, struct apoint *bkp) { - EXIT_IF (!in || !bkp, _("null pointer")); + EXIT_IF(!in || !bkp, _("null pointer")); bkp->start = in->start; bkp->dur = in->dur; bkp->state = in->state; - bkp->mesg = mem_strdup (in->mesg); + bkp->mesg = mem_strdup(in->mesg); if (in->note) - bkp->note = mem_strdup (in->note); + bkp->note = mem_strdup(in->note); } -void -apoint_llist_init (void) +void apoint_llist_init(void) { - LLIST_TS_INIT (&alist_p); + LLIST_TS_INIT(&alist_p); } /* @@ -88,60 +83,54 @@ apoint_llist_init (void) * list. No need to be thread safe, as only the main process remains when * calling this function. */ -void -apoint_llist_free (void) +void apoint_llist_free(void) { - LLIST_TS_FREE_INNER (&alist_p, apoint_free); - LLIST_TS_FREE (&alist_p); + LLIST_TS_FREE_INNER(&alist_p, apoint_free); + LLIST_TS_FREE(&alist_p); } /* Sets which appointment is highlighted. */ -void -apoint_hilt_set (int highlighted) +void apoint_hilt_set(int highlighted) { hilt = highlighted; } -void -apoint_hilt_decrease (void) +void apoint_hilt_decrease(int n) { - hilt--; + hilt -= n; } -void -apoint_hilt_increase (void) +void apoint_hilt_increase(int n) { - hilt++; + hilt += n; } /* Return which appointment is highlighted. */ -int -apoint_hilt (void) +int apoint_hilt(void) { - return (hilt); + return hilt; } -static int -apoint_cmp_start (struct apoint *a, struct apoint *b) +static int apoint_cmp_start(struct apoint *a, struct apoint *b) { - return (a->start < b->start ? -1 : (a->start == b->start ? 0 : 1)); + return a->start < b->start ? -1 : (a->start == b->start ? 0 : 1); } -struct apoint * -apoint_new (char *mesg, char *note, long start, long dur, char state) +struct apoint *apoint_new(char *mesg, char *note, long start, long dur, + char state) { struct apoint *apt; - apt = mem_malloc (sizeof (struct apoint)); - apt->mesg = mem_strdup (mesg); - apt->note = (note != NULL) ? mem_strdup (note) : NULL; + apt = mem_malloc(sizeof(struct apoint)); + apt->mesg = mem_strdup(mesg); + apt->note = (note != NULL) ? mem_strdup(note) : NULL; apt->state = state; apt->start = start; apt->dur = dur; - LLIST_TS_LOCK (&alist_p); - LLIST_TS_ADD_SORTED (&alist_p, apt, apoint_cmp_start); - LLIST_TS_UNLOCK (&alist_p); + LLIST_TS_LOCK(&alist_p); + LLIST_TS_ADD_SORTED(&alist_p, apt, apoint_cmp_start); + LLIST_TS_UNLOCK(&alist_p); return apt; } @@ -150,181 +139,148 @@ apoint_new (char *mesg, char *note, long start, long dur, char state) * Add an item in either the appointment or the event list, * depending if the start time is entered or not. */ -void -apoint_add (void) +void apoint_add(void) { #define LTIME 6 - char *mesg_1 = - _("Enter start time ([hh:mm] or [h:mm]), " - "leave blank for an all-day event : "); - char *mesg_2 = - _("Enter end time ([hh:mm] or [h:mm]) or duration (in minutes) : "); - char *mesg_3 = _("Enter description :"); - char *format_message_1 = - _("You entered an invalid start time, should be [h:mm] or [hh:mm]"); - char *format_message_2 = - _("You entered an invalid end time, should be [h:mm] or [hh:mm] or [mm]"); - char *enter_str = _("Press [Enter] to continue"); +#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[LTIME] = ""; + char item_time[LDUR] = ""; char item_mesg[BUFSIZ] = ""; - long apoint_duration = 0, apoint_start; + long apoint_start; unsigned heures, minutes; + unsigned apoint_duration; unsigned end_h, end_m; int is_appointment = 1; /* Get the starting time */ - do - { - 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; - } - else if (check_time (item_time) != 1) - { - status_mesg (format_message_1, enter_str); - (void)wgetch (win[STA].p); - } - else - (void)sscanf (item_time, "%u:%u", &heures, &minutes); - } - else - return; - } - while (check_time (item_time) != 1); + 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'; - do - { - status_mesg (mesg_2, ""); - if (getstring (win[STA].p, item_time, LTIME, 0, 1) != GETSTRING_VALID) - return; //nothing entered, cancel adding of event - else if (check_time (item_time) == 0) - { - status_mesg (format_message_2, enter_str); - (void)wgetch (win[STA].p); - } - else - { - if (check_time (item_time) == 2) - apoint_duration = atoi (item_time); - else if (check_time (item_time) == 1) - { - (void)sscanf (item_time, "%u:%u", &end_h, &end_m); - 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; - } - } - } + 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); } - while (check_time (item_time) == 0); + } else + return; } - else /* Insert the event Id */ + } 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); - (void)apoint_new (item_mesg, 0L, apoint_start, - min2sec (apoint_duration), 0L); - if (notify_bar ()) - notify_check_added (item_mesg, apoint_start, 0L); - } - else - (void)event_new (item_mesg, 0L, - date2sec (*calendar_get_slctd_day (), 12, 0), Id); - - if (hilt == 0) - hilt++; - } - wins_erase_status_bar (); + 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 (struct conf *conf, unsigned *nb_events, unsigned *nb_apoints) +void apoint_delete(unsigned *nb_events, unsigned *nb_apoints) { - char *choices = "[y/n] "; - char *del_app_str = _("Do you really want to delete this item ?"); + const char *del_app_str = _("Do you really want to delete this item ?"); long date; int nb_items = *nb_apoints + *nb_events; - unsigned go_for_deletion = 0; int to_be_removed = 0; - int answer = 0; - int deleted_item_type = 0; - - date = calendar_get_slctd_day_sec (); - - if (conf->confirm_delete) - { - status_mesg (del_app_str, choices); - answer = wgetch (win[STA].p); - if ((answer == 'y') && (nb_items != 0)) - go_for_deletion = 1; - else - { - wins_erase_status_bar (); - return; - } + + 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; } - else if (nb_items != 0) - go_for_deletion = 1; - - if (go_for_deletion) - { - if (nb_items != 0) - { - deleted_item_type = day_erase_item (date, hilt, ERASE_DONT_FORCE); - if (deleted_item_type == EVNT || deleted_item_type == RECUR_EVNT) - { - (*nb_events)--; - to_be_removed = 1; - } - else if (deleted_item_type == APPT || deleted_item_type == RECUR_APPT) - { - (*nb_apoints)--; - to_be_removed = 3; - } - else if (deleted_item_type == 0) - return; - 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 (nb_items == 1) - hilt = 0; - } + } + + 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) +int apoint_cut(unsigned *nb_events, unsigned *nb_apoints) { const int NBITEMS = *nb_apoints + *nb_events; int item_type, to_be_removed; @@ -333,20 +289,16 @@ apoint_cut (unsigned *nb_events, unsigned *nb_apoints) 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")); + 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) @@ -360,14 +312,13 @@ apoint_cut (unsigned *nb_events, unsigned *nb_apoints) } /* Paste a previously cut item. */ -void -apoint_paste (unsigned *nb_events, unsigned *nb_apoints, int cut_item_type) +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); + 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) @@ -379,81 +330,72 @@ apoint_paste (unsigned *nb_events, unsigned *nb_apoints, int cut_item_type) hilt++; } -unsigned -apoint_inday (struct apoint *i, long start) +unsigned apoint_inday(struct apoint *i, long start) { - if (i->start <= start + DAYINSEC && i->start + i->dur > start) - { - return (1); - } - return (0); + return (i->start <= start + DAYINSEC && i->start + i->dur > start); } -void -apoint_sec2str (struct apoint *o, int type, long day, char *start, char *end) +void apoint_sec2str(struct apoint *o, long day, char *start, char *end) { struct tm *lt; time_t t; - if (o->start < day && type == APPT) - (void)strncpy (start, "..:..", 6); - else - { - t = o->start; - lt = localtime (&t); - (void)snprintf (start, HRMIN_SIZE, "%02u:%02u", lt->tm_hour, lt->tm_min); - } - if (o->start + o->dur > day + DAYINSEC && type == APPT) - (void)strncpy (end, "..:..", 6); - else - { - t = o->start + o->dur; - lt = localtime (&t); - (void)snprintf (end, HRMIN_SIZE, "%02u:%02u", lt->tm_hour, lt->tm_min); - } + if (o->start < day) + strncpy(start, "..:..", 6); + else { + t = o->start; + lt = localtime(&t); + snprintf(start, HRMIN_SIZE, "%02u:%02u", lt->tm_hour, lt->tm_min); + } + if (o->start + o->dur > day + DAYINSEC) + strncpy(end, "..:..", 6); + else { + t = o->start + o->dur; + lt = localtime(&t); + snprintf(end, HRMIN_SIZE, "%02u:%02u", lt->tm_hour, lt->tm_min); + } } -void -apoint_write (struct apoint *o, FILE *f) +void apoint_write(struct apoint *o, FILE * f) { struct tm *lt; time_t t; t = o->start; - lt = localtime (&t); - (void)fprintf (f, "%02u/%02u/%04u @ %02u:%02u", - lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, lt->tm_hour, - lt->tm_min); + lt = localtime(&t); + fprintf(f, "%02u/%02u/%04u @ %02u:%02u", lt->tm_mon + 1, lt->tm_mday, + 1900 + lt->tm_year, lt->tm_hour, lt->tm_min); t = o->start + o->dur; - lt = localtime (&t); - (void)fprintf (f, " -> %02u/%02u/%04u @ %02u:%02u ", - lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, lt->tm_hour, - lt->tm_min); + lt = localtime(&t); + fprintf(f, " -> %02u/%02u/%04u @ %02u:%02u ", lt->tm_mon + 1, lt->tm_mday, + 1900 + lt->tm_year, lt->tm_hour, lt->tm_min); if (o->note != NULL) - (void)fprintf (f, ">%s ", o->note); + fprintf(f, ">%s ", o->note); if (o->state & APOINT_NOTIFY) - (void)fprintf (f, "!"); + fputc('!', f); else - (void)fprintf (f, "|"); + fputc('|', f); - (void)fprintf (f, "%s\n", o->mesg); + fprintf(f, "%s\n", o->mesg); } -struct apoint * -apoint_scan (FILE *f, struct tm start, struct tm end, char state, char *note) +struct apoint *apoint_scan(FILE * f, struct tm start, struct tm end, char state, + char *note) { char buf[BUFSIZ], *newline; time_t tstart, tend, t; - t = time (NULL); - (void)localtime (&t); + t = time(NULL); + localtime(&t); /* Read the appointment description */ - (void)fgets (buf, sizeof buf, f); - newline = strchr (buf, '\n'); + if (!fgets(buf, sizeof buf, f)) + return NULL; + + newline = strchr(buf, '\n'); if (newline) *newline = '\0'; @@ -464,63 +406,58 @@ apoint_scan (FILE *f, struct tm start, struct tm end, char state, char *note) end.tm_year -= 1900; end.tm_mon--; - tstart = mktime (&start); - tend = mktime (&end); - EXIT_IF (tstart == -1 || tend == -1 || tstart > tend, - _("date error in appointment")); - return (apoint_new (buf, note, tstart, tend - tstart, state)); + tstart = mktime(&start); + tend = mktime(&end); + EXIT_IF(tstart == -1 || tend == -1 || tstart > tend, + _("date error in appointment")); + 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) +struct apoint *apoint_get(long day, int pos) { - llist_item_t *i = LLIST_TS_FIND_NTH (&alist_p, pos, day, apoint_inday); + llist_item_t *i = LLIST_TS_FIND_NTH(&alist_p, pos, day, apoint_inday); if (i) - return LLIST_TS_GET_DATA (i); + return LLIST_TS_GET_DATA(i); - EXIT (_("item not found")); + EXIT(_("item not found")); /* NOTREACHED */ } -void -apoint_delete_bynum (long start, unsigned num, enum eraseflg flag) +void apoint_delete_bynum(long start, unsigned num, enum eraseflg flag) { llist_item_t *i; int need_check_notify = 0; - LLIST_TS_LOCK (&alist_p); - i = LLIST_TS_FIND_NTH (&alist_p, num, start, apoint_inday); + 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, flag); - break; - case ERASE_CUT: - apoint_free_bkp (ERASE_FORCE); - apoint_dup (apt, &bkp_cut_apoint); - erase_note (&apt->note, ERASE_FORCE_KEEP_NOTE); - /* FALLTHROUGH */ - default: - if (notify_bar ()) - need_check_notify = notify_same_item (apt->start); - LLIST_TS_REMOVE (&alist_p, i); - mem_free (apt->mesg); - if (flag != ERASE_FORCE_KEEP_NOTE && flag != ERASE_CUT) - erase_note (&apt->note, flag); - mem_free (apt); - if (need_check_notify) - notify_check_next_app (0); - break; - } - - LLIST_TS_UNLOCK (&alist_p); + 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; + } + + LLIST_TS_UNLOCK(&alist_p); } /* @@ -528,8 +465,7 @@ apoint_delete_bynum (long start, unsigned num, enum eraseflg flag) * the appointment panel. This is to help the appointment scroll function * to place beggining of the pad correctly. */ -static int -get_item_line (int item_nb, int nb_events_inday) +static int get_item_line(int item_nb, int nb_events_inday) { int separator = 2; int line = 0; @@ -538,7 +474,7 @@ get_item_line (int item_nb, int nb_events_inday) line = item_nb - 1; else line = nb_events_inday + separator - + (item_nb - (nb_events_inday + 1)) * 3 - 1; + + (item_nb - (nb_events_inday + 1)) * 3 - 1; return line; } @@ -546,15 +482,14 @@ get_item_line (int item_nb, int nb_events_inday) * Update (if necessary) the first displayed pad line to make the * appointment panel scroll down next time pnoutrefresh is called. */ -void -apoint_scroll_pad_down (int nb_events_inday, int win_length) +void apoint_scroll_pad_down(int nb_events_inday, int win_length) { int pad_last_line = 0; int item_first_line = 0, item_last_line = 0; int borders = 6; int awin_length = win_length - borders; - item_first_line = get_item_line (hilt, nb_events_inday); + item_first_line = get_item_line(hilt, nb_events_inday); if (hilt < nb_events_inday) item_last_line = item_first_line; else @@ -568,109 +503,84 @@ apoint_scroll_pad_down (int nb_events_inday, int win_length) * Update (if necessary) the first displayed pad line to make the * appointment panel scroll up next time pnoutrefresh is called. */ -void -apoint_scroll_pad_up (int nb_events_inday) +void apoint_scroll_pad_up(int nb_events_inday) { int item_first_line = 0; - item_first_line = get_item_line (hilt, nb_events_inday); + item_first_line = get_item_line(hilt, nb_events_inday); if (item_first_line < apad.first_onscreen) 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; } /* * Look in the appointment list if we have an item which starts before the item * stored in the notify_app structure (which is the next item to be notified). */ -struct notify_app * -apoint_check_next (struct notify_app *app, long start) +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); + LLIST_TS_LOCK(&alist_p); + i = LLIST_TS_FIND_FIRST(&alist_p, start, apoint_starts_after); - if (i) - { - struct apoint *apt = LLIST_TS_GET_DATA (i); - - if (apt->start <= app->time) - { - app->time = apt->start; - app->txt = mem_strdup (apt->mesg); - app->state = apt->state; - app->got_app = 1; - } + if (i) { + struct apoint *apt = LLIST_TS_GET_DATA(i); + + if (apt->start <= app->time) { + app->time = apt->start; + app->txt = mem_strdup(apt->mesg); + app->state = apt->state; + app->got_app = 1; } + } - LLIST_TS_UNLOCK (&alist_p); + LLIST_TS_UNLOCK(&alist_p); - return (app); -} - -/* - * Returns a structure of type struct apoint_list given a structure of type - * recur_apoint_s - */ -struct apoint * -apoint_recur_s2apoint_s (struct recur_apoint *p) -{ - struct apoint *a; - - a = mem_malloc (sizeof (struct apoint)); - a->mesg = mem_strdup (p->mesg); - a->start = p->start; - a->dur = p->dur; - return (a); + return app; } /* * Switch notification state. */ -void -apoint_switch_notify (void) +void apoint_switch_notify(void) { struct day_item *p; long date; int apoint_nb = 0, need_chk_notify; - p = day_get_item (hilt); + p = day_get_item(hilt); if (p->type != APPT && p->type != RECUR_APPT) return; - date = calendar_get_slctd_day_sec (); + 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); + 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); + LLIST_TS_LOCK(&alist_p); - struct apoint *apt = apoint_get (date, apoint_nb); + 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 (notify_bar()) + notify_check_added(apt->mesg, apt->start, apt->state); if (need_chk_notify) - notify_check_next_app (0); + notify_check_next_app(0); - LLIST_TS_UNLOCK (&alist_p); + LLIST_TS_UNLOCK(&alist_p); } /* Updates the Appointment panel */ -void -apoint_update_panel (int which_pan) +void apoint_update_panel(int which_pan) { int title_xpos; int bordr = 1; @@ -681,57 +591,53 @@ apoint_update_panel (int which_pan) struct date slctd_date; /* variable inits */ - slctd_date = *calendar_get_slctd_day (); - title_xpos = win[APP].w - (strlen (_(monthnames[slctd_date.mm - 1])) + 16); + slctd_date = *calendar_get_slctd_day(); + title_xpos = win[APP].w - (strlen(_(monthnames[slctd_date.mm - 1])) + 16); if (slctd_date.dd < 10) title_xpos++; - date = date2sec (slctd_date, 0, 0); - day_write_pad (date, app_width, app_length, hilt); + date = date2sec(slctd_date, 0, 0); + day_write_pad(date, app_width, app_length, (which_pan == APP) ? hilt : 0); /* Print current date in the top right window corner. */ - erase_window_part (win[APP].p, 1, title_lines, win[APP].w - 2, - win[APP].h - 2); - custom_apply_attr (win[APP].p, ATTR_HIGHEST); - mvwprintw (win[APP].p, title_lines, title_xpos, "%s %s %d, %d", - calendar_get_pom (date), _(monthnames[slctd_date.mm - 1]), - slctd_date.dd, slctd_date.yyyy); - custom_remove_attr (win[APP].p, ATTR_HIGHEST); + erase_window_part(win[APP].p, 1, title_lines, win[APP].w - 2, win[APP].h - 2); + custom_apply_attr(win[APP].p, ATTR_HIGHEST); + mvwprintw(win[APP].p, title_lines, title_xpos, "%s %s %d, %d", + calendar_get_pom(date), _(monthnames[slctd_date.mm - 1]), + slctd_date.dd, slctd_date.yyyy); + custom_remove_attr(win[APP].p, ATTR_HIGHEST); /* 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); - unsigned hilt_bar = (which_pan == APP) ? 1 : 0; - int sbar_top = highend + title_lines + 1; - - if ((sbar_top + sbar_length) > win[APP].h - 1) - sbar_length = win[APP].h - 1 - sbar_top; - draw_scrollbar (win[APP].p, sbar_top, win[APP].w - 2, sbar_length, - title_lines + 1, win[APP].h - 1, hilt_bar); - } - - wnoutrefresh (win[APP].p); - pnoutrefresh (apad.ptrwin, apad.first_onscreen, 0, - win[APP].y + title_lines + 1, win[APP].x + bordr, - win[APP].y + win[APP].h - 2 * bordr, - win[APP].x + win[APP].w - 3 * bordr); + 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); + unsigned hilt_bar = (which_pan == APP) ? 1 : 0; + int sbar_top = highend + title_lines + 1; + + if ((sbar_top + sbar_length) > win[APP].h - 1) + sbar_length = win[APP].h - 1 - sbar_top; + draw_scrollbar(win[APP].p, sbar_top, win[APP].w - 2, sbar_length, + title_lines + 1, win[APP].h - 1, hilt_bar); + } + + wnoutrefresh(win[APP].p); + pnoutrefresh(apad.ptrwin, apad.first_onscreen, 0, + win[APP].y + title_lines + 1, win[APP].x + bordr, + win[APP].y + win[APP].h - 2 * bordr, + win[APP].x + win[APP].w - 3 * bordr); } -void -apoint_paste_item (void) +void apoint_paste_item(void) { long bkp_time, bkp_start; - bkp_time = get_item_time (bkp_cut_apoint.start); - bkp_start = calendar_get_slctd_day_sec () + bkp_time; - (void)apoint_new (bkp_cut_apoint.mesg, bkp_cut_apoint.note, - bkp_start, bkp_cut_apoint.dur, - bkp_cut_apoint.state); + 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); - if (notify_bar ()) - notify_check_added (bkp_cut_apoint.mesg, bkp_start, bkp_cut_apoint.state); + if (notify_bar()) + notify_check_added(bkp_cut_apoint.mesg, bkp_start, bkp_cut_apoint.state); - apoint_free_bkp (ERASE_FORCE_KEEP_NOTE); + apoint_free_bkp(); } @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -45,112 +45,114 @@ #include "calcurse.h" +/* Long options */ +enum { + OPT_FMT_APT = 1000, + OPT_FMT_RAPT, + OPT_FMT_EV, + OPT_FMT_REV, + OPT_FMT_TODO, + OPT_READ_ONLY +}; + /* * Print Calcurse usage and exit. */ -static void -usage () +static void usage(void) { - char *arg_usage = - _("Usage: calcurse [-h|-v] [-N] [-an] [-t[num]] [-i<file>] [-x[format]]\n" - " [-d <date>|<num>] [-s[date]] [-r[range]]\n" - " [-c<file> | -D<dir>] [-S<regex>] [--status]\n"); - fputs (arg_usage, stdout); + 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" + " [--read-only]\n"); + fputs(arg_usage, stdout); } -static void -usage_try () +static void usage_try(void) { - char *arg_usage_try = _("Try 'calcurse -h' for more information.\n"); - fputs (arg_usage_try, stdout); + const char *arg_usage_try = _("Try 'calcurse -h' for more information.\n"); + fputs(arg_usage_try, stdout); } /* * Print Calcurse version with a short copyright text and exit. */ -static void -version_arg () +static void version_arg(void) { - char vtitle[BUFSIZ]; - char *vtext = - _("\nCopyright (c) 2004-2011 calcurse Development Team.\n" + const char *vtext = + _("\nCopyright (c) 2004-2012 calcurse Development Team.\n" "This is free software; see the source for copying conditions.\n"); - (void)snprintf (vtitle, BUFSIZ, _("Calcurse %s - text-based organizer\n"), - VERSION); - fputs (vtitle, stdout); - fputs (vtext, stdout); + fprintf(stdout, _("Calcurse %s - text-based organizer\n"), VERSION); + fputs(vtext, stdout); } /* * Print the command line options and exit. */ -static void -help_arg () +static void help_arg(void) { - char htitle[BUFSIZ]; - char *htext = - _("\nMiscellaneous:\n" - " -h, --help\n" - " print this help and exit.\n" - "\n -v, --version\n" - " print calcurse version and exit.\n" - "\n --status\n" - " display the status of running instances of calcurse.\n" - "\nFiles:\n" - " -c <file>, --calendar <file>\n" - " specify the calendar <file> to use (incompatible with '-D').\n" - "\n -D <dir>, --directory <dir>\n" - " specify the data directory to use (incompatible with '-c').\n" - "\tIf not specified, the default directory is ~/.calcurse\n" - "\nNon-interactive:\n" - " -a, --appointment\n" - " print events and appointments for current day and exit.\n" - "\n -d <date|num>, --day <date|num>\n" - " print events and appointments for <date> or <num> upcoming days and" - "\n\texit. To specify both a starting date and a range, use the\n" - "\t'--startday' and the '--range' option.\n" - "\n -i <file>, --import <file>\n" - " import the icalendar data contained in <file>. \n" - "\n -n, --next\n" - " print next appointment within upcoming 24 hours " - "and exit. Also given\n\tis the remaining time before this " - "next appointment.\n" - "\n -N, --note\n" - " when used with the '-a' or '-t' flag, also print note content\n" - " if one is associated with the displayed item.\n" - "\n -r[num], --range[=num]\n" - " print events and appointments for the [num] number of days" - "\n\tand exit. If no [num] is given, a range of 1 day is considered.\n" - "\n -s[date], --startday[=date]\n" - " print events and appointments from [date] and exit.\n" - "\tIf no [date] is given, the current day is considered.\n" - "\n -S<regex>, --search=<regex>\n" - " search for the given regular expression within events, appointments,\n" - "\tand todos description.\n" - "\n -t[num], --todo[=num]\n" - " print todo list and exit. If the optional number [num] is given,\n" - "\tthen only todos having a priority equal to [num] will be returned.\n" - "\tThe priority number must be between 1 (highest) and 9 (lowest).\n" - "\tIt is also possible to specify '0' for the priority, in which case\n" - "\tonly completed tasks will be shown.\n" - "\n -x[format], --export[=format]\n" - " export user data to the specified format. Events, appointments and\n" - "\ttodos are converted and echoed to stdout.\n" - "\tTwo possible formats are available: 'ical' and 'pcal'.\n" - "\tIf the optional argument format is not given, ical format is\n" - "\tselected by default.\n" - "\tnote: redirect standard output to export data to a file,\n" - "\tby issuing a command such as: calcurse --export > calcurse.dat\n" - "\nFor more information, type '?' from within Calcurse, " - "or read the manpage.\n" - "Mail bug reports and suggestions to <misc@calcurse.org>.\n"); - - (void)snprintf (htitle, BUFSIZ, _("Calcurse %s - text-based organizer\n"), - VERSION); - fputs (htitle, stdout); - usage (); - fputs (htext, stdout); + const char *htext = + _("\nMiscellaneous:\n" + " -h, --help\n" + " print this help and exit.\n" + "\n -v, --version\n" + " print calcurse version and exit.\n" + "\n --status\n" + " display the status of running instances of calcurse.\n" + "\n --read-only\n" + " 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" + "\n -D <dir>, --directory <dir>\n" + " specify the data directory to use (incompatible with '-c').\n" + "\tIf not specified, the default directory is ~/.calcurse\n" + "\nNon-interactive:\n" + " -a, --appointment\n" + " print events and appointments for current day and exit.\n" + "\n -d <date|num>, --day <date|num>\n" + " print events and appointments for <date> or <num> upcoming days and" + "\n\texit. To specify both a starting date and a range, use the\n" + "\t'--startday' and the '--range' option.\n" + "\n -g, --gc\n" + " run the garbage collector for note files and exit. \n" + "\n -i <file>, --import <file>\n" + " import the icalendar data contained in <file>. \n" + "\n -n, --next\n" + " print next appointment within upcoming 24 hours " + "and exit. Also given\n\tis the remaining time before this " + "next appointment.\n" + "\n -r[num], --range[=num]\n" + " print events and appointments for the [num] number of days" + "\n\tand exit. If no [num] is given, a range of 1 day is considered.\n" + "\n -s[date], --startday[=date]\n" + " print events and appointments from [date] and exit.\n" + "\tIf no [date] is given, the current day is considered.\n" + "\n -S<regex>, --search=<regex>\n" + " search for the given regular expression within events, appointments,\n" + "\tand todos description.\n" + "\n -t[num], --todo[=num]\n" + " print todo list and exit. If the optional number [num] is given,\n" + "\tthen only todos having a priority equal to [num] will be returned.\n" + "\tThe priority number must be between 1 (highest) and 9 (lowest).\n" + "\tIt is also possible to specify '0' for the priority, in which case\n" + "\tonly completed tasks will be shown.\n" + "\n -x[format], --export[=format]\n" + " export user data to the specified format. Events, appointments and\n" + "\ttodos are converted and echoed to stdout.\n" + "\tTwo possible formats are available: 'ical' and 'pcal'.\n" + "\tIf the optional argument format is not given, ical format is\n" + "\tselected by default.\n" + "\tnote: redirect standard output to export data to a file,\n" + "\tby issuing a command such as: calcurse --export > calcurse.dat\n" + "\nFor more information, type '?' from within Calcurse, " + "or read the manpage.\n" + "Mail bug reports and suggestions to <misc@calcurse.org>.\n"); + + fprintf(stdout, _("Calcurse %s - text-based organizer\n"), VERSION); + usage(); + fputs(htext, stdout); } /* @@ -164,78 +166,24 @@ help_arg () * The status is obtained by looking at pid files in user data directory * (.calcurse.pid and .daemon.pid). */ -static void -status_arg (void) +static void status_arg(void) { int cpid, dpid; - cpid = io_get_pid (path_cpid); - dpid = io_get_pid (path_dpid); + cpid = io_get_pid(path_cpid); + dpid = io_get_pid(path_dpid); - EXIT_IF (cpid && dpid, - _("Error: both calcurse (pid: %d) and its daemon (pid: %d)\n" - "seem to be running at the same time!\n" - "Please check manually and restart calcurse.\n"), - cpid, dpid); + EXIT_IF(cpid && dpid, + _("Error: both calcurse (pid: %d) and its daemon (pid: %d)\n" + "seem to be running at the same time!\n" + "Please check manually and restart calcurse.\n"), cpid, dpid); if (cpid) - fprintf (stdout, _("calcurse is running (pid %d)\n"), cpid); + fprintf(stdout, _("calcurse is running (pid %d)\n"), cpid); else if (dpid) - fprintf (stdout, _("calcurse is running in background (pid %d)\n"), dpid); + fprintf(stdout, _("calcurse is running in background (pid %d)\n"), dpid); else - fprintf (stdout, _("calcurse is not running\n")); -} - -/* - * Display note contents if one is asociated with the currently displayed item - * (to be used together with the '-a' or '-t' flag in non-interactive mode). - * Each line begins with nbtab tabs. - * Print "No note file found", if the notefile does not exists. - * - * (patch submitted by Erik Saule). - */ -static void -print_notefile (FILE *out, char *filename, int nbtab) -{ - char path_to_notefile[BUFSIZ]; - FILE *notefile; - char linestarter[BUFSIZ]; - char buffer[BUFSIZ]; - int i; - int printlinestarter = 1; - - if (nbtab < BUFSIZ) - { - for (i = 0; i < nbtab; i++) - linestarter[i] = '\t'; - linestarter[nbtab] = '\0'; - } - else - linestarter[0] = '\0'; - - (void)snprintf (path_to_notefile, BUFSIZ, "%s/%s", path_notes, filename); - notefile = fopen (path_to_notefile, "r"); - if (notefile) - { - while (fgets (buffer, BUFSIZ, notefile) != 0) - { - if (printlinestarter) - { - fputs (linestarter, out); - printlinestarter = 0; - } - fputs (buffer, out); - if (buffer[strlen (buffer) - 1] == '\n') - printlinestarter = 1; - } - fputs ("\n", out); - file_close (notefile, __FILE_POS__); - } - else - { - fputs (linestarter, out); - fputs (_("No note file found\n"), out); - } + puts(_("calcurse is not running\n")); } /* @@ -245,14 +193,13 @@ print_notefile (FILE *out, char *filename, int nbtab) * If priority == 0, only completed tasks will be displayed. * If regex is not null, only the matching todos are printed. */ -static void -todo_arg (int priority, int print_note, regex_t *regex) +static void todo_arg(int priority, const char *format, regex_t * regex) { llist_item_t *i; int title = 1; - char *titlestr, priority_str[BUFSIZ] = ""; - char *all_todos_title = _("to do:\n"); - char *completed_title = _("completed tasks:\n"); + const char *titlestr; + const char *all_todos_title = _("to do:\n"); + const char *completed_title = _("completed tasks:\n"); titlestr = priority == 0 ? completed_title : all_todos_title; @@ -264,49 +211,32 @@ todo_arg (int priority, int print_note, regex_t *regex) } \ } while (0) -#define DISPLAY_TODO do { \ - (void)snprintf (priority_str, BUFSIZ, "%d. ", abs (todo->id)); \ - fputs (priority_str, stdout); \ - fputs (todo->mesg, stdout); \ - fputs ("\n", stdout); \ - if (print_note && todo->note) \ - print_notefile (stdout, todo->note, 1); \ - } while (0) - - LLIST_FOREACH (&todolist, i) - { - struct todo *todo = LLIST_TS_GET_DATA (i); - if (regex && regexec (regex, todo->mesg, 0, 0, 0) != 0) - continue; - - if (todo->id < 0) /* completed task */ - { - if (priority == 0) - { - DISPLAY_TITLE; - DISPLAY_TODO; - } - } - else - { - if (priority < 0 || todo->id == priority) - { - DISPLAY_TITLE; - DISPLAY_TODO; - } - } + LLIST_FOREACH(&todolist, i) { + struct todo *todo = LLIST_TS_GET_DATA(i); + if (regex && regexec(regex, todo->mesg, 0, 0, 0) != 0) + continue; + + if (todo->id < 0) { /* completed task */ + if (priority == 0) { + DISPLAY_TITLE; + print_todo(format, todo); + } + } else { + if (priority < 0 || todo->id == priority) { + DISPLAY_TITLE; + print_todo(format, todo); + } } + } #undef DISPLAY_TITLE -#undef DISPLAY_TODO } /* Print the next appointment within the upcoming 24 hours. */ -static void -next_arg (void) +static void next_arg(void) { struct notify_app next_app; - const long current_time = now (); + const long current_time = now(); int time_left, hours_left, min_left; char mesg[BUFSIZ]; @@ -314,37 +244,35 @@ next_arg (void) next_app.got_app = 0; next_app.txt = NULL; - next_app = *recur_apoint_check_next (&next_app, current_time, get_today ()); - next_app = *apoint_check_next (&next_app, current_time); - - if (next_app.got_app) - { - time_left = next_app.time - current_time; - hours_left = (time_left / HOURINSEC); - min_left = (time_left - hours_left * HOURINSEC) / MININSEC; - fputs (_("next appointment:\n"), stdout); - (void)snprintf (mesg, BUFSIZ, " [%02d:%02d] %s\n", hours_left, min_left, - next_app.txt); - fputs (mesg, stdout); - mem_free (next_app.txt); - } + next_app = *recur_apoint_check_next(&next_app, current_time, get_today()); + next_app = *apoint_check_next(&next_app, current_time); + + if (next_app.got_app) { + time_left = next_app.time - current_time; + hours_left = (time_left / HOURINSEC); + min_left = (time_left - hours_left * HOURINSEC) / MININSEC; + fputs(_("next appointment:\n"), stdout); + snprintf(mesg, BUFSIZ, " [%02d:%02d] %s\n", hours_left, min_left, + next_app.txt); + fputs(mesg, stdout); + mem_free(next_app.txt); + } } /* * Print the date on stdout. */ -static void -arg_print_date (long date, struct conf *conf) +static void arg_print_date(long date) { char date_str[BUFSIZ]; time_t t; struct tm *lt; t = date; - lt = localtime (&t); - strftime (date_str, BUFSIZ, conf->output_datefmt, lt); - fputs (date_str, stdout); - fputs (":\n", stdout); + lt = localtime(&t); + strftime(date_str, BUFSIZ, conf.output_datefmt, lt); + fputs(date_str, stdout); + fputs(":\n", stdout); } /* @@ -354,18 +282,17 @@ arg_print_date (long date, struct conf *conf) * If regex is not null, only the matching appointments or events are printed. */ static int -app_arg (int add_line, struct date *day, long date, int print_note, - struct conf *conf, regex_t *regex) +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) { llist_item_t *i, *j; long today; unsigned print_date = 1; int app_found = 0; - char apoint_start_time[HRMIN_SIZE]; - char apoint_end_time[HRMIN_SIZE]; if (date == 0) - today = get_sec_date (*day); + today = get_sec_date(*day); else today = date; @@ -374,159 +301,114 @@ app_arg (int add_line, struct date *day, long date, int print_note, * 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; - - app_found = 1; - if (add_line) - { - fputs ("\n", stdout); - add_line = 0; - } - if (print_date) - { - arg_print_date (today, conf); - print_date = 0; - } - fputs (" * ", stdout); - fputs (re->mesg, stdout); - fputs ("\n", stdout); - if (print_note && re->note) - print_notefile (stdout, re->note, 2); + 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; + + app_found = 1; + if (add_line) { + fputs("\n", stdout); + add_line = 0; } - - LLIST_FIND_FOREACH (&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, conf); - print_date = 0; - } - fputs (" * ", stdout); - fputs (ev->mesg, stdout); - fputs ("\n", stdout); - if (print_note && ev->note) - print_notefile (stdout, ev->note, 2); + 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); + 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); - - 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); - } + 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); - } + 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 (apt->start <= recur_apoint_inday (ra, today)) - ra = NULL; - else - apt = NULL; - } + 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, conf); - print_date = 0; - } - apoint_sec2str (apt, APPT, today, apoint_start_time, apoint_end_time); - fputs (" - ", stdout); - fputs (apoint_start_time, stdout); - fputs (" -> ", stdout); - fputs (apoint_end_time, stdout); - fputs ("\n\t", stdout); - fputs (apt->mesg, stdout); - fputs ("\n", stdout); - if (print_note && apt->note) - print_notefile (stdout, apt->note, 2); - 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, conf); - print_date = 0; - } - apt = apoint_recur_s2apoint_s (ra); - apoint_sec2str (apt, RECUR_APPT, today, apoint_start_time, - apoint_end_time); - mem_free (apt->mesg); - mem_free (apt); - fputs (" - ", stdout); - fputs (apoint_start_time, stdout); - fputs (" -> ", stdout); - fputs (apoint_end_time, stdout); - fputs ("\n\t", stdout); - fputs (ra->mesg, stdout); - fputs ("\n", stdout); - if (print_note && ra->note) - print_notefile (stdout, ra->note, 2); - apt = NULL; - j = LLIST_TS_FIND_NEXT (j, today, recur_apoint_inday); - } + 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); } + } - LLIST_TS_UNLOCK (&recur_alist_p); - LLIST_TS_UNLOCK (&alist_p); + LLIST_TS_UNLOCK(&recur_alist_p); + LLIST_TS_UNLOCK(&alist_p); - return (app_found); + return app_found; } -static void -more_info (void) +static void more_info(void) { - fputs (_("\nFor more information, type '?' from within Calcurse, " - "or read the manpage.\n"), stdout); - fputs (_("Mail bug reports and suggestions to " - "<misc@calcurse.org>.\n"), stdout); + fputs(_("\nFor more information, type '?' from within Calcurse, " + "or read the manpage.\n"), stdout); + fputs(_("Mail bug reports and suggestions to " + "<misc@calcurse.org>.\n"), stdout); } /* @@ -535,23 +417,24 @@ more_info (void) * to format the output correctly. */ static void -display_app (struct tm *t, int numdays, int add_line, int print_note, - struct conf *conf, regex_t *regex) +display_app(struct tm *t, int numdays, int add_line, const char *fmt_apt, + const char *fmt_rapt, const char *fmt_ev, const char *fmt_rev, + regex_t * regex) { int i, app_found; struct date day; - for (i = 0; i < numdays; i++) - { - day.dd = t->tm_mday; - day.mm = t->tm_mon + 1; - day.yyyy = t->tm_year + 1900; - app_found = app_arg (add_line, &day, 0, print_note, conf, regex); - if (app_found) - add_line = 1; - t->tm_mday++; - (void)mktime (t); - } + for (i = 0; i < numdays; i++) { + day.dd = t->tm_mday; + day.mm = t->tm_mon + 1; + day.yyyy = t->tm_year + 1900; + app_found = app_arg(add_line, &day, 0, fmt_apt, fmt_rapt, fmt_ev, + fmt_rev, regex); + if (app_found) + add_line = 1; + t->tm_mday++; + mktime(t); + } } /* @@ -559,8 +442,9 @@ display_app (struct tm *t, int numdays, int add_line, int print_note, * days. */ static void -date_arg (char *ddate, int add_line, int print_note, struct conf *conf, - regex_t *regex) +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; @@ -573,44 +457,38 @@ date_arg (char *ddate, int add_line, int print_note, struct conf *conf, * 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); - - /* - * 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); - t = *localtime (&timer); - display_app (&t, numdays, add_line, print_note, conf, regex); + 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++; } - else - { /* a date was entered */ - if (parse_date (ddate, conf->input_datefmt, (int *)&day.yyyy, - (int *)&day.mm, (int *)&day.dd, NULL)) - { - (void)app_arg (add_line, &day, 0, print_note, conf, regex); - } - else - { - char outstr[BUFSIZ]; - fputs (_("Argument to the '-d' flag is not valid\n"), stderr); - (void)snprintf (outstr, BUFSIZ, - "Possible argument format are: '%s' or 'n'\n", - DATEFMT_DESC (conf->input_datefmt)); - fputs (_(outstr), stdout); - more_info (); - } + if (num_digit == arg_len) + numdays = atoi(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. + */ + timer = time(NULL); + t = *localtime(&timer); + display_app(&t, numdays, add_line, fmt_apt, fmt_rapt, fmt_ev, fmt_rev, + regex); + } 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); + } else { + char outstr[BUFSIZ]; + fputs(_("Argument to the '-d' flag is not valid\n"), stderr); + snprintf(outstr, BUFSIZ, + "Possible argument format are: '%s' or 'n'\n", + DATEFMT_DESC(conf.input_datefmt)); + fputs(_(outstr), stdout); + more_info(); } + } } /* @@ -622,8 +500,9 @@ date_arg (char *ddate, int add_line, int print_note, struct conf *conf, * Many thanks to Erik Saule for providing this function. */ static void -date_arg_extended (char *startday, char *range, int add_line, int print_note, - struct conf *conf, regex_t *regex) +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; static struct tm t; @@ -632,95 +511,91 @@ date_arg_extended (char *startday, char *range, int add_line, int print_note, /* * 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) - numdays = atoi (range); + if (range != NULL) { + arg_len = strlen(range); + for (i = 0; i <= arg_len - 1; i++) { + if (!isdigit(range[i])) + error = 1; } - timer = time (NULL); - t = *localtime (&timer); - if (startday != NULL) - { - if (parse_date (startday, conf->input_datefmt, (int *)&t.tm_year, - (int *)&t.tm_mon, (int *)&t.tm_mday, NULL)) - { - t.tm_year -= 1900; - t.tm_mon--; - (void)mktime (&t); - } - else - { - error = 1; - } - } - if (!error) - { - display_app (&t, numdays, add_line, print_note, conf, regex); - } - else - { - char outstr[BUFSIZ]; - fputs (_("Argument is not valid\n"), stderr); - (void)snprintf (outstr, BUFSIZ, - "Argument format for -s and --startday is: '%s'\n", - DATEFMT_DESC (conf->input_datefmt)); - fputs (_(outstr), stdout); - fputs (_("Argument format for -r and --range is: 'n'\n"), stdout); - more_info (); + if (!error) + numdays = atoi(range); + } + timer = time(NULL); + t = *localtime(&timer); + if (startday != NULL) { + if (parse_date(startday, conf.input_datefmt, (int *)&t.tm_year, + (int *)&t.tm_mon, (int *)&t.tm_mday, NULL)) { + t.tm_year -= 1900; + t.tm_mon--; + mktime(&t); + } else { + error = 1; } + } + if (!error) { + display_app(&t, numdays, add_line, fmt_apt, fmt_rapt, fmt_ev, fmt_rev, + regex); + } else { + char outstr[BUFSIZ]; + fputs(_("Argument is not valid\n"), stderr); + snprintf(outstr, BUFSIZ, + "Argument format for -s and --startday is: '%s'\n", + DATEFMT_DESC(conf.input_datefmt)); + fputs(_(outstr), stdout); + fputs(_("Argument format for -r and --range is: 'n'\n"), stdout); + more_info(); + } } - /* * Parse the command-line arguments and call the appropriate * routines to handle those arguments. Also initialize the data paths. */ -int -parse_args (int argc, char **argv, struct conf *conf) +int parse_args(int argc, char **argv) { int ch, add_line = 0; 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 iflag = 0; /* -i: import data */ - int nflag = 0; /* -n: print next appointment */ - int Nflag = 0; /* -N: also print note content with apps and todos */ - int rflag = 0; /* -r: specify the range of days to consider */ - int sflag = 0; /* -s: specify the first day to consider */ - int Sflag = 0; /* -S: specify a regex to search for */ - int tflag = 0; /* -t: print todo list */ - int vflag = 0; /* -v: print version number */ - int xflag = 0; /* -x: export data */ + 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 */ + int nflag = 0; /* -n: print next appointment */ + int rflag = 0; /* -r: specify the range of days to consider */ + int sflag = 0; /* -s: specify the first day to consider */ + int Sflag = 0; /* -S: specify a regex to search for */ + int tflag = 0; /* -t: print todo list */ + int vflag = 0; /* -v: print version number */ + int xflag = 0; /* -x: export data */ + /* Format strings */ + const char *fmt_apt = " - %S -> %E\n\t%m\n"; + const char *fmt_rapt = " - %S -> %E\n\t%m\n"; + const char *fmt_ev = " * %m\n"; + const char *fmt_rev = " * %m\n"; + const char *fmt_todo = "%p. %m\n"; int tnum = 0, xfmt = 0, non_interactive = 0, multiple_flag = 0, load_data = 0; - char *ddate = "", *cfile = NULL, *range = NULL, *startday = NULL; - char *datadir = NULL, *ifile = NULL; + const char *ddate = "", *cfile = NULL, *range = NULL, *startday = NULL; + const char *datadir = NULL, *ifile = NULL; regex_t reg, *preg = NULL; /* Long options only */ - int statusflag = 0; /* --status: get the status of running instances */ - enum - { + int statusflag = 0; /* --status: get the status of running instances */ + enum { STATUS_OPT = CHAR_MAX + 1 }; - static char *optstr = "hvnNax::t::d:c:r::s::S:D:i:"; + static const char *optstr = "ghvnNax::t::d:c:r::s::S:D:i:"; struct option longopts[] = { {"appointment", no_argument, NULL, 'a'}, {"calendar", required_argument, NULL, 'c'}, {"day", required_argument, NULL, 'd'}, {"directory", required_argument, NULL, 'D'}, + {"gc", no_argument, NULL, 'g'}, {"help", no_argument, NULL, 'h'}, {"import", required_argument, NULL, 'i'}, {"next", no_argument, NULL, 'n'}, @@ -732,255 +607,253 @@ parse_args (int argc, char **argv, struct conf *conf) {"todo", optional_argument, NULL, 't'}, {"version", no_argument, NULL, 'v'}, {"export", optional_argument, NULL, 'x'}, + + {"format-apt", required_argument, NULL, OPT_FMT_APT}, + {"format-recur-apt", required_argument, NULL, OPT_FMT_RAPT}, + {"format-event", required_argument, NULL, OPT_FMT_EV}, + {"format-recur-event", required_argument, NULL, OPT_FMT_REV}, + {"format-todo", required_argument, NULL, OPT_FMT_TODO}, + {"read-only", no_argument, NULL, OPT_READ_ONLY}, {NULL, no_argument, NULL, 0} }; - while ((ch = getopt_long (argc, argv, optstr, longopts, NULL)) != -1) - { - switch (ch) - { - case STATUS_OPT: - statusflag = 1; - break; - case 'a': - aflag = 1; - multiple_flag++; - load_data++; - break; - case 'c': - cflag = 1; - multiple_flag++; - cfile = optarg; - load_data++; - break; - case 'd': - dflag = 1; - multiple_flag++; - load_data++; - ddate = optarg; - break; - case 'D': - Dflag = 1; - datadir = optarg; - break; - case 'h': - hflag = 1; - break; - case 'i': - iflag = 1; - multiple_flag++; - load_data++; - ifile = optarg; - break; - case 'n': - nflag = 1; - multiple_flag++; - load_data++; - break; - case 'N': - Nflag = 1; - break; - case 'r': - rflag = 1; - multiple_flag++; - load_data++; - range = optarg; - break; - case 's': - sflag = 1; - multiple_flag++; - load_data++; - startday = optarg; - break; - case 'S': - EXIT_IF (Sflag > 0, - _("Can not handle more than one regular expression.")); - Sflag = 1; - if (regcomp (®, optarg, REG_EXTENDED)) - EXIT (_("Could not compile regular expression.")); - preg = ® - break; - case 't': - tflag = 1; - multiple_flag++; - load_data++; - add_line = 1; - if (optarg != NULL) - { - tnum = atoi (optarg); - if (tnum < 0 || tnum > 9) - { - usage (); - usage_try (); - return (EXIT_FAILURE); - } - } - else - tnum = -1; - break; - case 'v': - vflag = 1; - break; - case 'x': - xflag = 1; - multiple_flag++; - load_data++; - if (optarg != NULL) - { - if (strcmp (optarg, "ical") == 0) - xfmt = IO_EXPORT_ICAL; - else if (strcmp (optarg, "pcal") == 0) - xfmt = IO_EXPORT_PCAL; - else - { - fputs (_("Argument for '-x' should be either " - "'ical' or 'pcal'\n"), stderr); - usage (); - usage_try (); - return EXIT_FAILURE; - } - } - else - { - xfmt = IO_EXPORT_ICAL; - } - break; - default: - usage (); - usage_try (); - unknown_flag = 1; - non_interactive = 1; - /* NOTREACHED */ + while ((ch = getopt_long(argc, argv, optstr, longopts, NULL)) != -1) { + switch (ch) { + case STATUS_OPT: + statusflag = 1; + break; + case 'a': + aflag = 1; + multiple_flag++; + load_data++; + break; + case 'c': + cflag = 1; + multiple_flag++; + cfile = optarg; + load_data++; + break; + case 'd': + dflag = 1; + multiple_flag++; + load_data++; + ddate = optarg; + break; + case 'D': + Dflag = 1; + datadir = optarg; + break; + case 'h': + hflag = 1; + break; + case 'g': + gflag = 1; + break; + case 'i': + iflag = 1; + multiple_flag++; + load_data++; + ifile = optarg; + break; + case 'n': + nflag = 1; + multiple_flag++; + load_data++; + break; + case 'r': + rflag = 1; + multiple_flag++; + load_data++; + range = optarg; + break; + case 's': + sflag = 1; + multiple_flag++; + load_data++; + startday = optarg; + break; + case 'S': + EXIT_IF(Sflag > 0, _("Can not handle more than one regular expression.")); + Sflag = 1; + if (regcomp(®, optarg, REG_EXTENDED)) + EXIT(_("Could not compile regular expression.")); + preg = ® + break; + case 't': + tflag = 1; + multiple_flag++; + load_data++; + add_line = 1; + if (optarg != NULL) { + tnum = atoi(optarg); + if (tnum < 0 || tnum > 9) { + usage(); + usage_try(); + return EXIT_FAILURE; } + } else + tnum = -1; + break; + case 'v': + vflag = 1; + break; + case 'x': + xflag = 1; + multiple_flag++; + load_data++; + if (optarg != NULL) { + if (strcmp(optarg, "ical") == 0) + xfmt = IO_EXPORT_ICAL; + else if (strcmp(optarg, "pcal") == 0) + xfmt = IO_EXPORT_PCAL; + else { + fputs(_("Argument for '-x' should be either " + "'ical' or 'pcal'\n"), stderr); + usage(); + usage_try(); + return EXIT_FAILURE; + } + } else { + xfmt = IO_EXPORT_ICAL; + } + break; + case OPT_FMT_APT: + fmt_apt = optarg; + break; + case OPT_FMT_RAPT: + fmt_rapt = optarg; + break; + case OPT_FMT_EV: + fmt_ev = optarg; + break; + case OPT_FMT_REV: + fmt_rev = optarg; + break; + case OPT_FMT_TODO: + fmt_todo = optarg; + break; + case OPT_READ_ONLY: + read_only = 1; + break; + default: + usage(); + usage_try(); + unknown_flag = 1; + non_interactive = 1; + /* NOTREACHED */ } + } argc -= optind; - if (argc >= 1) - { - usage (); - 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); - usage (); - usage_try (); - return EXIT_FAILURE; - } - else - { - if (unknown_flag) - { - non_interactive = 1; - } - else if (hflag) - { - help_arg (); - non_interactive = 1; - } - else if (vflag) - { - version_arg (); - non_interactive = 1; - } - else if (statusflag) - { - io_init (cfile, datadir); - status_arg (); - non_interactive = 1; - } - else if (multiple_flag) - { - if (load_data) - { - io_init (cfile, datadir); - io_check_dir (path_dir, (int *)0); - io_check_dir (path_notes, (int *)0); - } - if (iflag) - { - io_check_file (path_apts, (int *)0); - io_check_file (path_todo, (int *)0); - /* Get default pager in case we need to show a log file. */ - vars_init (conf); - io_load_app (); - io_load_todo (); - io_import_data (IO_IMPORT_ICAL, conf, ifile); - io_save_apts (); - io_save_todo (); - non_interactive = 1; - } - if (xflag) - { - io_check_file (path_apts, (int *)0); - io_check_file (path_todo, (int *)0); - io_load_app (); - io_load_todo (); - io_export_data (xfmt, conf); - non_interactive = 1; - return non_interactive; - } - if (tflag) - { - io_check_file (path_todo, (int *)0); - io_load_todo (); - todo_arg (tnum, Nflag, preg); - non_interactive = 1; - } - if (nflag) - { - io_check_file (path_apts, (int *)0); - io_load_app (); - next_arg (); - non_interactive = 1; - } - if (dflag || rflag || sflag) - { - io_check_file (path_apts, (int *)0); - io_check_file (path_conf, (int *)0); - io_load_app (); - custom_load_conf (conf, 0); /* To get output date format. */ - if (dflag) - date_arg (ddate, add_line, Nflag, conf, preg); - if (rflag || sflag) - date_arg_extended (startday, range, add_line, Nflag, conf, - preg); - non_interactive = 1; - } - else if (aflag) - { - struct date day; - - io_check_file (path_apts, (int *)0); - io_check_file (path_conf, (int *)0); - vars_init (conf); - custom_load_conf (conf, 0); /* To get output date format. */ - io_load_app (); - day.dd = day.mm = day.yyyy = 0; - (void)app_arg (add_line, &day, 0, Nflag, conf, preg); - non_interactive = 1; - } - } - else - { - non_interactive = 0; - io_init (cfile, datadir); - } + if (argc >= 1) { + usage(); + 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); + usage(); + usage_try(); + return EXIT_FAILURE; + } else { + if (unknown_flag) { + non_interactive = 1; + } else if (hflag) { + help_arg(); + non_interactive = 1; + } else if (vflag) { + version_arg(); + non_interactive = 1; + } else if (statusflag) { + io_init(cfile, datadir); + status_arg(); + 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_load_app(); + io_load_todo(); + note_gc(); + non_interactive = 1; + } else if (multiple_flag) { + if (load_data) { + io_init(cfile, datadir); + io_check_dir(path_dir, NULL); + io_check_dir(path_notes, NULL); + } + if (iflag) { + io_check_file(path_apts, NULL); + io_check_file(path_todo, NULL); + /* Get default pager in case we need to show a log file. */ + vars_init(); + io_load_app(); + io_load_todo(); + io_import_data(IO_IMPORT_ICAL, ifile); + io_save_apts(); + io_save_todo(); + non_interactive = 1; + } + if (xflag) { + io_check_file(path_apts, NULL); + io_check_file(path_todo, NULL); + io_load_app(); + io_load_todo(); + io_export_data(xfmt); + non_interactive = 1; + return non_interactive; + } + if (tflag) { + io_check_file(path_todo, NULL); + io_load_todo(); + todo_arg(tnum, fmt_todo, preg); + non_interactive = 1; + } + if (nflag) { + io_check_file(path_apts, NULL); + 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_load_app(); + config_load(); /* To get output date format. */ + if (dflag) + date_arg(ddate, add_line, fmt_apt, fmt_rapt, fmt_ev, fmt_rev, preg); + if (rflag || sflag) + date_arg_extended(startday, range, add_line, fmt_apt, + fmt_rapt, fmt_ev, fmt_rev, preg); + non_interactive = 1; + } else if (aflag) { + struct date day; + + io_check_file(path_apts, NULL); + io_check_file(path_conf, NULL); + vars_init(); + config_load(); /* To get output date format. */ + io_load_app(); + day.dd = day.mm = day.yyyy = 0; + app_arg(add_line, &day, 0, fmt_apt, fmt_rapt, fmt_ev, fmt_rev, preg); + non_interactive = 1; + } + } else { + non_interactive = 0; + io_init(cfile, datadir); } + } if (preg) - regfree (preg); + regfree(preg); return non_interactive; } diff --git a/src/calcurse.c b/src/calcurse.c index 662f185..9e42eee 100644 --- a/src/calcurse.c +++ b/src/calcurse.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -39,541 +39,484 @@ #include "calcurse.h" /* + * Store the events and appointments for the selected day and reset the + * appointment highlight pointer if a new day was selected. + */ +static struct day_items_nb do_storage(int day_changed) +{ + struct day_items_nb inday = *day_process_storage(calendar_get_slctd_day(), + day_changed, &inday); + + if (day_changed) + apoint_hilt_set(1); + + return inday; +} + +/* * Calcurse is a text-based personal organizer which helps keeping track * of events and everyday tasks. It contains a calendar, a 'todo' list, * and puts your appointments in order. The user interface is configurable, * and one can choose between different color schemes and layouts. * All of the commands are documented within an online help system. */ -int -main (int argc, char **argv) +int main(int argc, char **argv) { - struct conf conf; struct day_items_nb inday; - int background, foreground; - int non_interactive; int no_data_file = 1; - int sav_hilt_app = 0; - int sav_hilt_tod = 0; int cut_item = 0; - unsigned do_storage = 0; - unsigned do_update = 1; - unsigned day_changed = 0; - char *no_color_support = - _("Sorry, colors are not supported by your terminal\n" - "(Press [ENTER] to continue)"); - char *quit_message = _("Do you really want to quit ?"); - char choices[] = "[y/n] "; + int count; #if ENABLE_NLS - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); #endif /* ENABLE_NLS */ /* Thread-safe data structure init */ - apoint_llist_init (); - recur_apoint_llist_init (); + apoint_llist_init(); + recur_apoint_llist_init(); /* Initialize non-thread-safe data structures. */ - event_llist_init (); - todo_init_list (); + event_llist_init(); + todo_init_list(); /* * Begin by parsing and handling command line arguments. * The data path is also initialized here. */ - non_interactive = parse_args (argc, argv, &conf); - if (non_interactive) - exit_calcurse (EXIT_SUCCESS); - else - { - no_data_file = io_check_data_files (); - dmon_stop (); - io_set_lock (); - } + if (parse_args(argc, argv)) { + /* Non-interactive mode. */ + exit_calcurse(EXIT_SUCCESS); + } else { + no_data_file = io_check_data_files(); + dmon_stop(); + io_set_lock(); + } /* Begin of interactive mode with ncurses interface. */ - sigs_init (); /* signal handling init */ - initscr (); /* start the curses mode */ - cbreak (); /* control chars generate a signal */ - noecho (); /* controls echoing of typed chars */ - curs_set (0); /* make cursor invisible */ - calendar_set_current_date (); - notify_init_vars (); - wins_get_config (); + sigs_init(); /* signal handling init */ + initscr(); /* start the curses mode */ + cbreak(); /* control chars generate a signal */ + noecho(); /* controls echoing of typed chars */ + curs_set(0); /* make cursor invisible */ + calendar_set_current_date(); + notify_init_vars(); + wins_get_config(); /* Check if terminal supports color. */ - if (has_colors ()) - { - colorize = 1; - background = COLOR_BLACK; - foreground = COLOR_WHITE; - start_color (); + if (has_colors()) { + colorize = 1; + background = COLOR_BLACK; + foreground = COLOR_WHITE; + start_color(); #ifdef NCURSES_VERSION - if (use_default_colors () != ERR) - { - background = -1; - foreground = -1; - } -#endif /* NCURSES_VERSION */ - - /* Color assignment */ - init_pair (COLR_RED, COLOR_RED, background); - init_pair (COLR_GREEN, COLOR_GREEN, background); - init_pair (COLR_YELLOW, COLOR_YELLOW, background); - init_pair (COLR_BLUE, COLOR_BLUE, background); - init_pair (COLR_MAGENTA, COLOR_MAGENTA, background); - init_pair (COLR_CYAN, COLOR_CYAN, background); - init_pair (COLR_DEFAULT, foreground, background); - init_pair (COLR_HIGH, COLOR_BLACK, COLOR_GREEN); - init_pair (COLR_CUSTOM, COLOR_RED, background); - - } - else - { - colorize = 0; - background = COLOR_BLACK; + if (use_default_colors() != ERR) { + background = -1; + foreground = -1; } +#endif /* NCURSES_VERSION */ - vars_init (&conf); - wins_init (); - wins_slctd_init (); - notify_init_bar (); - wins_reset_status_page (); + /* Color assignment */ + init_pair(COLR_RED, COLOR_RED, background); + init_pair(COLR_GREEN, COLOR_GREEN, background); + init_pair(COLR_YELLOW, COLOR_YELLOW, background); + init_pair(COLR_BLUE, COLOR_BLUE, background); + init_pair(COLR_MAGENTA, COLOR_MAGENTA, background); + init_pair(COLR_CYAN, COLOR_CYAN, background); + init_pair(COLR_DEFAULT, foreground, background); + init_pair(COLR_HIGH, COLOR_BLACK, COLOR_GREEN); + init_pair(COLR_CUSTOM, COLOR_RED, background); + } else { + colorize = 0; + background = COLOR_BLACK; + } + + vars_init(); + wins_init(); + wins_slctd_init(); + notify_init_bar(); + wins_reset_status_page(); /* * Read the data from files : first the user * configuration (the display is then updated), and then * the todo list, appointments and events. */ - custom_load_conf (&conf, background); - wins_erase_status_bar (); - io_load_keys (conf.pager); - io_load_todo (); - io_load_app (); - wins_reinit (); - if (notify_bar ()) - notify_start_main_thread (); - wins_update (); - io_startup_screen (conf.skip_system_dialogs, no_data_file); - inday = *day_process_storage (0, day_changed, &inday); - wins_slctd_set (CAL); - wins_update (); - calendar_start_date_thread (); + config_load(); + wins_erase_status_bar(); + io_load_keys(conf.pager); + io_load_todo(); + io_load_app(); + wins_reinit(); + if (conf.system_dialogs) { + wins_update(FLAG_ALL); + io_startup_screen(no_data_file); + } + inday = *day_process_storage(0, 0, &inday); + wins_slctd_set(CAL); + wins_update(FLAG_ALL); + + /* Start miscellaneous threads. */ + if (notify_bar()) + notify_start_main_thread(); + calendar_start_date_thread(); if (conf.periodic_save > 0) - io_start_psave_thread (&conf); + io_start_psave_thread(); /* User input */ - for (;;) - { - int key; - - do_update = 1; - key = keys_getch (win[STA].p); - switch (key) - { - case ERR: - do_update = 0; - break; - - case KEY_GENERIC_REDRAW: - resize = 1; - break; - - case KEY_GENERIC_CHANGE_VIEW: - wins_reset_status_page (); - /* Need to save the previously highlighted event. */ - switch (wins_slctd ()) - { - case TOD: - sav_hilt_tod = todo_hilt (); - todo_hilt_set (0); - break; - case APP: - sav_hilt_app = apoint_hilt (); - apoint_hilt_set (0); - break; - default: - break; - } - wins_slctd_next (); - - /* Select the event to highlight. */ - switch (wins_slctd ()) - { - case TOD: - if ((sav_hilt_tod == 0) && (todo_nb () != 0)) - todo_hilt_set (1); - else - todo_hilt_set (sav_hilt_tod); - break; - case APP: - if ((sav_hilt_app == 0) - && ((inday.nb_events + inday.nb_apoints) != 0)) - apoint_hilt_set (1); - else - apoint_hilt_set (sav_hilt_app); - break; - default: - break; - } - break; - - case KEY_GENERIC_OTHER_CMD: - wins_other_status_page (wins_slctd ()); - 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); - do_storage = 1; - day_changed = 1; - 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 :")); - break; - - case KEY_GENERIC_CONFIG_MENU: - wins_erase_status_bar (); - custom_config_bar (); - while ((key = wgetch (win[STA].p)) != 'q') - { - switch (key) - { - case 'C': - case 'c': - if (has_colors ()) - custom_color_config (); - else - { - colorize = 0; - wins_erase_status_bar (); - mvwprintw (win[STA].p, 0, 0, _(no_color_support)); - wgetch (win[STA].p); - } - break; - case 'L': - case 'l': - custom_layout_config (); - break; - case 'G': - case 'g': - custom_general_config (&conf); - break; - case 'N': - case 'n': - notify_config_bar (); - break; - case 'K': - case 'k': - custom_keys_config (); - break; - case 's': - case 'S': - custom_sidebar_config (); - break; - } - wins_reset (); - wins_update (); - do_storage = 1; - wins_erase_status_bar (); - custom_config_bar (); - } - wins_update (); - break; - - case KEY_GENERIC_ADD_APPT: - apoint_add (); - do_storage = 1; - break; - - case KEY_GENERIC_ADD_TODO: - todo_new_item (); - if (todo_hilt () == 0 && todo_nb () == 1) - todo_hilt_increase (); - break; - - case KEY_ADD_ITEM: - switch (wins_slctd ()) - { - case APP: - apoint_add (); - do_storage = 1; - break; - case TOD: - todo_new_item (); - if (todo_hilt () == 0 && todo_nb () == 1) - todo_hilt_increase (); - break; - default: - break; - } - break; - - case KEY_EDIT_ITEM: - if (wins_slctd () == APP && apoint_hilt () != 0) - day_edit_item (&conf); - else if (wins_slctd () == TOD && todo_hilt () != 0) - todo_edit_item (); - do_storage = 1; - break; - - case KEY_DEL_ITEM: - if (wins_slctd () == APP && apoint_hilt () != 0) - apoint_delete (&conf, &inday.nb_events, &inday.nb_apoints); - else if (wins_slctd () == TOD && todo_hilt () != 0) - todo_delete (&conf); - do_storage = 1; - break; - - case KEY_GENERIC_CUT: - if (wins_slctd () == APP && apoint_hilt () != 0) - { - cut_item = apoint_cut (&inday.nb_events, &inday.nb_apoints); - do_storage = 1; - } - break; - - case KEY_GENERIC_PASTE: - if (wins_slctd () == APP) - { - apoint_paste (&inday.nb_events, &inday.nb_apoints, cut_item); - cut_item = 0; - do_storage = 1; - } - break; + for (;;) { + int key; - case KEY_REPEAT_ITEM: - if (wins_slctd () == APP && apoint_hilt () != 0) - recur_repeat_item (&conf); - do_storage = 1; - break; - - case KEY_FLAG_ITEM: - if (wins_slctd () == APP && apoint_hilt () != 0) - apoint_switch_notify (); - else if (wins_slctd () == TOD && todo_hilt () != 0) - todo_flag (); - do_storage = 1; - 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); - } - break; - - case KEY_EDIT_NOTE: - if (wins_slctd () == APP && apoint_hilt () != 0) - day_edit_note (conf.editor); - else if (wins_slctd () == TOD && todo_hilt () != 0) - todo_edit_note (conf.editor); - do_storage = 1; - 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); - break; - - case KEY_GENERIC_HELP: - wins_status_bar (); - help_screen (); - break; - - case KEY_GENERIC_SAVE: - io_save_cal (&conf, IO_SAVE_DISPLAY_BAR); - break; - - case KEY_GENERIC_IMPORT: - wins_erase_status_bar (); - io_import_data (IO_IMPORT_ICAL, &conf, NULL); - do_storage = 1; - 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, &conf); - break; - case 'P': - case 'p': - io_export_data (IO_EXPORT_PCAL, &conf); - break; - } - wins_reset (); - wins_update (); - do_storage = 1; - wins_erase_status_bar (); - io_export_bar (); - } - wins_update (); - break; - - case KEY_GENERIC_NEXT_DAY: - case KEY_MOVE_RIGHT: - if (wins_slctd () == CAL || key == KEY_GENERIC_NEXT_DAY) - { - do_storage = 1; - day_changed = 1; - calendar_move (RIGHT); - } - break; - - case KEY_GENERIC_PREV_DAY: - case KEY_MOVE_LEFT: - if (wins_slctd () == CAL || key == KEY_GENERIC_PREV_DAY) - { - do_storage = 1; - day_changed = 1; - calendar_move (LEFT); - } - break; - - case KEY_GENERIC_PREV_WEEK: - case KEY_MOVE_UP: - if (wins_slctd () == CAL || key == KEY_GENERIC_PREV_WEEK) - { - do_storage = 1; - day_changed = 1; - calendar_move (UP); - } - else if ((wins_slctd () == APP) && (apoint_hilt () > 1)) - { - apoint_hilt_decrease (); - apoint_scroll_pad_up (inday.nb_events); - } - else if ((wins_slctd () == TOD) && (todo_hilt () > 1)) - { - todo_hilt_decrease (); - if (todo_hilt_pos () < 0) - todo_first_decrease (); - } - break; - - case KEY_GENERIC_NEXT_WEEK: - case KEY_MOVE_DOWN: - if (wins_slctd () == CAL || key == KEY_GENERIC_NEXT_WEEK) - { - do_storage = 1; - day_changed = 1; - calendar_move (DOWN); - } - else if ((wins_slctd () == APP) && - (apoint_hilt () < inday.nb_events + inday.nb_apoints)) - { - apoint_hilt_increase (); - apoint_scroll_pad_down (inday.nb_events, win[APP].h); - } - else if ((wins_slctd () == TOD) && (todo_hilt () < todo_nb ())) - { - todo_hilt_increase (); - if (todo_hilt_pos () == win[TOD].h - 4) - todo_first_increase (); - } - break; - - case KEY_START_OF_WEEK: - if (wins_slctd () == CAL) - { - do_storage = 1; - day_changed = 1; - calendar_move (WEEK_START); - } - break; - - case KEY_END_OF_WEEK: - if (wins_slctd () == CAL) - { - do_storage = 1; - day_changed = 1; - calendar_move (WEEK_END); - } - break; - - case KEY_GENERIC_SCROLL_UP: - if (wins_slctd () == CAL) - calendar_view_prev (); - break; - - case KEY_GENERIC_SCROLL_DOWN: - if (wins_slctd () == CAL) - calendar_view_next (); - break; - - case KEY_GENERIC_QUIT: - if (conf.auto_save) - io_save_cal (&conf, IO_SAVE_DISPLAY_BAR); - - if (conf.confirm_quit) - { - status_mesg (_(quit_message), choices); - key = wgetch (win[STA].p); - if (key == 'y') - exit_calcurse (EXIT_SUCCESS); - else - { - wins_erase_status_bar (); - break; - } - } - else - exit_calcurse (EXIT_SUCCESS); - break; + if (resize) { + resize = 0; + wins_reset(); + } - default: - do_update = 0; + key = keys_getch(win[STA].p, &count); + 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; } - - if (do_storage) - { - inday = *day_process_storage (calendar_get_slctd_day (), - day_changed, &inday); - do_storage = !do_storage; - if (day_changed) - { - sav_hilt_app = 0; - day_changed = !day_changed; - if ((wins_slctd () == APP) && - (inday.nb_events + inday.nb_apoints != 0)) - apoint_hilt_set (1); - } + 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_NEXT_DAY: + case KEY_MOVE_RIGHT: + if (wins_slctd() == CAL || key == KEY_GENERIC_NEXT_DAY) { + calendar_move(RIGHT, count); + inday = do_storage(1); + wins_update(FLAG_CAL | FLAG_APP); + } + break; + + case KEY_GENERIC_PREV_DAY: + case KEY_MOVE_LEFT: + if (wins_slctd() == CAL || key == KEY_GENERIC_PREV_DAY) { + calendar_move(LEFT, 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(UP, 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(DOWN, 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_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; - if (resize) - { - resize = 0; - do_update = 0; - wins_reset (); - } + case KEY_RESIZE: + case ERR: + /* Do not reset the count parameter on resize or error. */ + continue; - if (do_update) - wins_update (); + default: + break; } + + count = 0; + } } diff --git a/src/calcurse.h b/src/calcurse.h index 091d16a..9efb4fd 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -40,13 +40,13 @@ #include "config.h" #ifdef HAVE_NCURSES_H -# include <ncurses.h> +#include <ncurses.h> #elif defined HAVE_NCURSES_NCURSES_H -# include <ncurses/ncurses.h> +#include <ncurses/ncurses.h> #elif defined HAVE_NCURSESW_NCURSES_H -# include <ncursesw/ncurses.h> +#include <ncursesw/ncurses.h> #else -# error "Missing ncurses header. Aborting..." +#error "Missing ncurses header. Aborting..." #endif #include <pthread.h> @@ -60,24 +60,24 @@ /* Internationalization. */ #if ENABLE_NLS -# include <locale.h> -# include <libintl.h> -# undef _ -# define _(String) gettext(String) -# ifdef gettext_noop -# define N_(String) gettext_noop(String) -# else -# define N_(String) (String) -# endif +#include <locale.h> +#include <libintl.h> +#undef _ +#define _(String) gettext(String) +#ifdef gettext_noop +#define N_(String) gettext_noop(String) +#else +#define N_(String) (String) +#endif #else /* NLS disabled */ -# define _(String) (String) -# define N_(String) (String) -# define textdomain(String) (String) -# define gettext(String) (String) -# define dgettext(String) (String) -# define dcgettext(String) (String) -# define bindtextdomain(String) (String) -# define bind_textdomain_codeset(Domain,Codeset) (Codeset) +#define _(String) (String) +#define N_(String) (String) +#define textdomain(String) (String) +#define gettext(String) (String) +#define dgettext(String) (String) +#define dcgettext(String) (String) +#define bindtextdomain(String) (String) +#define bind_textdomain_codeset(Domain,Codeset) (Codeset) #endif /* ENABLE_NLS */ /* Paths configuration. */ @@ -103,132 +103,148 @@ #define DEFAULT_EDITOR "vi" #define DEFAULT_PAGER "less" -#define ATTR_FALSE 0 -#define ATTR_TRUE 1 -#define ATTR_LOWEST 2 -#define ATTR_LOW 3 -#define ATTR_MIDDLE 4 -#define ATTR_HIGH 5 -#define ATTR_HIGHEST 6 +#define ATTR_FALSE 0 +#define ATTR_TRUE 1 +#define ATTR_LOWEST 2 +#define ATTR_LOW 3 +#define ATTR_MIDDLE 4 +#define ATTR_HIGH 5 +#define ATTR_HIGHEST 6 -#define STATUSHEIGHT 2 -#define NOTESIZ 6 +#define STATUSHEIGHT 2 +#define MAX_NOTESIZ 40 +#define TMPEXTSIZ 6 /* Format for appointment hours is: HH:MM */ #define HRMIN_SIZE 6 /* Maximum number of colors available. */ -#define NBUSERCOLORS 6 +#define NBUSERCOLORS 6 /* Side bar width acceptable boundaries. */ #define SBARMINWIDTH 32 #define SBARMAXWIDTHPERC 50 /* Related to date manipulation. */ -#define DAYINSEC 86400 -#define HOURINSEC 3600 -#define MININSEC 60 -#define YEARINDAYS 365 #define YEARINMONTHS 12 -#define WEEKINDAYS 7 +#define YEARINDAYS 365 #define TM_YEAR_BASE 1900 +#define WEEKINDAYS 7 +#define DAYINHOURS 24 +#define HOURINMIN 60 +#define MININSEC 60 + +#define WEEKINHOURS (WEEKINDAYS * DAYINHOURS) +#define WEEKINMIN (WEEKINHOURS * HOURINMIN) +#define WEEKINSEC (WEEKINMIN * MININSEC) +#define DAYINMIN (DAYINHOURS * HOURINMIN) +#define DAYINSEC (DAYINMIN * MININSEC) +#define HOURINSEC (HOURINMIN * MININSEC) + /* Calendar window. */ -#define CALHEIGHT 12 +#define CALHEIGHT 12 /* Key definitions. */ #define CTRLVAL 0x1F #define CTRL(x) ((x) & CTRLVAL) -#define ESCAPE 27 -#define TAB 9 +#define ESCAPE 27 +#define TAB 9 #define SPACE 32 -#define KEYS_KEYLEN 3 /* length of each keybinding */ -#define KEYS_LABELEN 8 /* length of command description */ -#define KEYS_CMDS_PER_LINE 6 /* max number of commands per line */ - -#define ERROR_MSG(...) do { \ - char msg[BUFSIZ]; \ - int len; \ - \ - len = snprintf (msg, BUFSIZ, "%s: %d: ", __FILE__, __LINE__); \ - (void)snprintf (msg + len, BUFSIZ - len, __VA_ARGS__); \ - if (ui_mode == UI_CURSES) \ - fatalbox (msg); \ - else \ - (void)fprintf (stderr, "%s\n", msg); \ +#define KEYS_KEYLEN 3 /* length of each keybinding */ +#define KEYS_LABELEN 8 /* length of command description */ +#define KEYS_CMDS_PER_LINE 6 /* max number of commands per line */ + +/* Size of the hash table the note garbage collector uses. */ +#define NOTE_GC_HSIZE 1024 + +#define ERROR_MSG(...) do { \ + char msg[BUFSIZ]; \ + int len; \ + \ + len = snprintf (msg, BUFSIZ, "%s: %d: ", __FILE__, __LINE__); \ + snprintf (msg + len, BUFSIZ - len, __VA_ARGS__); \ + if (ui_mode == UI_CURSES) \ + fatalbox (msg); \ + else \ + fprintf (stderr, "%s\n", msg); \ } while (0) -#define WARN_MSG(...) do { \ - char msg[BUFSIZ]; \ - \ - (void)snprintf (msg, BUFSIZ, __VA_ARGS__); \ - if (ui_mode == UI_CURSES) \ - warnbox (msg); \ - else \ - (void)fprintf (stderr, "%s\n", msg); \ +#define WARN_MSG(...) do { \ + char msg[BUFSIZ]; \ + \ + snprintf (msg, BUFSIZ, __VA_ARGS__); \ + if (ui_mode == UI_CURSES) \ + warnbox (msg); \ + else \ + fprintf (stderr, "%s\n", msg); \ } while (0) -#define EXIT(...) do { \ - ERROR_MSG(__VA_ARGS__); \ - if (ui_mode == UI_CURSES) \ - exit_calcurse (EXIT_FAILURE); \ - else \ - exit (EXIT_FAILURE); \ +#define EXIT(...) do { \ + ERROR_MSG(__VA_ARGS__); \ + if (ui_mode == UI_CURSES) \ + exit_calcurse (EXIT_FAILURE); \ + else \ + exit (EXIT_FAILURE); \ } while (0) -#define EXIT_IF(cond, ...) do { \ - if ((cond)) \ - EXIT(__VA_ARGS__); \ +#define EXIT_IF(cond, ...) do { \ + if ((cond)) \ + EXIT(__VA_ARGS__); \ } while (0) -#define RETURN_IF(cond, ...) do { \ - if ((cond)) \ - { \ - ERROR_MSG(__VA_ARGS__); \ - return; \ - } \ +#define RETURN_IF(cond, ...) do { \ + if ((cond)) \ + { \ + ERROR_MSG(__VA_ARGS__); \ + return; \ + } \ } while (0) -#define RETVAL_IF(cond, val, ...) do { \ - if ((cond)) \ - { \ - ERROR_MSG(__VA_ARGS__); \ - return (val); \ - } \ +#define RETVAL_IF(cond, val, ...) do { \ + if ((cond)) \ + { \ + ERROR_MSG(__VA_ARGS__); \ + return (val); \ + } \ } while (0) -#define STRING_BUILD(str) {str, sizeof (str) - 1} #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #define __FILE_POS__ __FILE__ ":" TOSTRING(__LINE__) +#define UTF8_MAXLEN 6 +#define UTF8_LENGTH(ch) ((unsigned char)ch >= 0xFC ? 6 : \ + ((unsigned char)ch >= 0xF8 ? 5 : \ + ((unsigned char)ch >= 0xF0 ? 4 : \ + ((unsigned char)ch >= 0xE0 ? 3 : \ + ((unsigned char)ch >= 0xC0 ? 2 : 1))))) +#define UTF8_ISCONT(ch) ((unsigned char)ch >= 0x80 && \ + (unsigned char)ch <= 0xBF) + #define MAX(x,y) ((x)>(y)?(x):(y)) #define MIN(x,y) ((x)<(y)?(x):(y)) /* General configuration variables. */ struct conf { - unsigned auto_save; - unsigned periodic_save; - unsigned confirm_quit; - unsigned confirm_delete; - unsigned skip_system_dialogs; - unsigned skip_progress_bar; - char *editor; - char *pager; - char output_datefmt[BUFSIZ]; /* format for displaying date */ - int input_datefmt; /* format for reading date */ + unsigned auto_save; + unsigned auto_gc; + unsigned periodic_save; + unsigned confirm_quit; + unsigned confirm_delete; + unsigned system_dialogs; + unsigned progress_bar; + const char *editor; + const char *pager; + char output_datefmt[BUFSIZ]; /* format for displaying date */ + int input_datefmt; /* format for reading date */ }; /* Daemon-related configuration. */ struct dmon_conf { - unsigned enable; /* launch daemon automatically when exiting */ - unsigned log; /* log daemon activity */ -}; - -struct string { - const char *str; - const int len; + unsigned enable; /* launch daemon automatically when exiting */ + unsigned log; /* log daemon activity */ }; enum datefmt { @@ -239,16 +255,13 @@ enum datefmt { DATE_FORMATS }; -#define DATEFMT(datefmt) (datefmt == DATEFMT_MMDDYYYY ? "%m/%d/%Y" : \ - (datefmt == DATEFMT_DDMMYYYY ? "%d/%m/%Y" : \ - (datefmt == DATEFMT_YYYYMMDD ? "%Y/%m/%d" : "%Y-%m-%d"))) +#define DATEFMT(datefmt) (datefmt == DATEFMT_MMDDYYYY ? "%m/%d/%Y" : \ + (datefmt == DATEFMT_DDMMYYYY ? "%d/%m/%Y" : \ + (datefmt == DATEFMT_YYYYMMDD ? "%Y/%m/%d" : "%Y-%m-%d"))) -#define DATEFMT_DESC(datefmt) (datefmt == DATEFMT_MMDDYYYY ? \ - _("mm/dd/yyyy") : \ - (datefmt == DATEFMT_DDMMYYYY ? \ - _("dd/mm/yyyy") : \ - (datefmt == DATEFMT_YYYYMMDD ? \ - _("yyyy/mm/dd") : _("yyyy-mm-dd")))) +#define DATEFMT_DESC(datefmt) (datefmt == DATEFMT_MMDDYYYY ? \ + _("mm/dd/yyyy") : (datefmt == DATEFMT_DDMMYYYY ? _("dd/mm/yyyy") : \ + (datefmt == DATEFMT_YYYYMMDD ? _("yyyy/mm/dd") : _("yyyy-mm-dd")))) struct date { unsigned dd; @@ -257,33 +270,32 @@ struct date { }; /* Appointment definition. */ -struct apoint -{ - long start; /* seconds since 1 jan 1970 */ - long dur; /* duration of the appointment in seconds */ +struct apoint { + long start; /* seconds since 1 jan 1970 */ + long dur; /* duration of the appointment in seconds */ #define APOINT_NULL 0x0 -#define APOINT_NOTIFY 0x1 /* Item needs to be notified */ -#define APOINT_NOTIFIED 0x2 /* Item was already notified */ - int state; +#define APOINT_NOTIFY 0x1 /* Item needs to be notified */ +#define APOINT_NOTIFIED 0x2 /* Item was already notified */ + int state; - char *mesg; - char *note; + char *mesg; + char *note; }; /* Event definition. */ struct event { - int id; /* event identifier */ - long day; /* seconds since 1 jan 1970 */ - char *mesg; - char *note; + int id; /* event identifier */ + long day; /* seconds since 1 jan 1970 */ + char *mesg; + char *note; }; /* Todo item definition. */ struct todo { - char *mesg; - int id; - char *note; + char *mesg; + int id; + char *note; }; /* Number of items in current day. */ @@ -294,18 +306,18 @@ struct day_items_nb { /* 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 */ + 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 */ + long st; /* beggining of the considered day, in seconds */ }; enum recur_type { @@ -319,43 +331,43 @@ enum recur_type { /* To describe an item's repetition. */ struct rpt { - enum recur_type type; /* repetition type */ - int freq; /* repetition frequence */ - long until; /* ending date for repeated event */ + enum recur_type type; /* repetition type */ + int freq; /* repetition frequence */ + long until; /* ending date for repeated event */ }; /* Recurrent appointment definition. */ struct recur_apoint { - struct rpt *rpt; /* information about repetition */ - llist_t exc; /* days when the item should not be repeated */ - long start; /* beggining of the appointment */ - long dur; /* duration of the appointment */ - char state; /* 8 bits to store item state */ - char *mesg; /* appointment description */ - char *note; /* note attached to appointment */ + struct rpt *rpt; /* information about repetition */ + llist_t exc; /* days when the item should not be repeated */ + long start; /* beggining of the appointment */ + long dur; /* duration of the appointment */ + char state; /* 8 bits to store item state */ + char *mesg; /* appointment description */ + char *note; /* note attached to appointment */ }; /* Reccurent event definition. */ struct recur_event { - struct rpt *rpt; /* information about repetition */ - llist_t exc; /* days when the item should not be repeated */ - int id; /* event type */ - long day; /* day at which event occurs */ - char *mesg; /* event description */ - char *note; /* note attached to event */ + struct rpt *rpt; /* information about repetition */ + llist_t exc; /* days when the item should not be repeated */ + int id; /* event type */ + long day; /* day at which event occurs */ + char *mesg; /* event description */ + char *note; /* note attached to event */ }; struct notify_app { - long time; - int got_app; - char *txt; - char state; - pthread_mutex_t mutex; + long time; + int got_app; + char *txt; + char state; + pthread_mutex_t mutex; }; struct io_file { FILE *fd; - char name[BUFSIZ]; + char name[BUFSIZ]; }; /* Available keys. */ @@ -395,6 +407,7 @@ enum key { KEY_DEL_ITEM, KEY_EDIT_ITEM, KEY_VIEW_ITEM, + KEY_PIPE_ITEM, KEY_FLAG_ITEM, KEY_REPEAT_ITEM, KEY_EDIT_NOTE, @@ -408,8 +421,8 @@ enum key { /* To describe a key binding. */ struct binding { - char *label; - enum key action; + char *label; + enum key action; }; enum win { @@ -421,6 +434,13 @@ enum win { NBWINS }; +#define FLAG_CAL (1 << CAL) +#define FLAG_APP (1 << APP) +#define FLAG_TOD (1 << TOD) +#define FLAG_NOT (1 << NOT) +#define FLAG_STA (1 << STA) +#define FLAG_ALL ((1 << NBWINS) - 1) + enum ui_mode { UI_CURSES, UI_CMDLINE, @@ -429,40 +449,41 @@ enum ui_mode { /* Generic window structure. */ struct window { - WINDOW *p; /* pointer to window */ - unsigned w; /* width */ - unsigned h; /* height */ - int x; /* x position */ - int y; /* y position */ + WINDOW *p; /* pointer to window */ + unsigned w; /* width */ + unsigned h; /* height */ + int x; /* x position */ + int y; /* y position */ }; /* Generic scrolling window structure. */ struct scrollwin { - struct window win; - struct window pad; - unsigned first_visible_line; - unsigned total_lines; - char label[BUFSIZ]; + struct window win; + struct window pad; + unsigned first_visible_line; + unsigned total_lines; + const char *label; }; /* Pad structure to handle scrolling. */ struct pad { - int width; - int length; - int first_onscreen; /* first line to be displayed inside window */ - WINDOW *ptrwin; /* pointer to the pad window */ + int width; + int length; + int first_onscreen; /* first line to be displayed inside window */ + WINDOW *ptrwin; /* pointer to the pad window */ }; /* Notification bar definition. */ struct nbar { - int show; /* display or hide the notify-bar */ - int cntdwn; /* warn when time left before next app - becomes lesser than cntdwn */ - char datefmt[BUFSIZ]; /* format for displaying date */ - char timefmt[BUFSIZ]; /* format for displaying time */ - char cmd[BUFSIZ]; /* notification command */ - char *shell; /* user shell to launch notif. cmd */ - pthread_mutex_t mutex; + unsigned show; /* display or hide the notify-bar */ + int cntdwn; /* warn when time left before next app + becomes lesser than cntdwn */ + char datefmt[BUFSIZ]; /* format for displaying date */ + char timefmt[BUFSIZ]; /* format for displaying time */ + char cmd[BUFSIZ]; /* notification command */ + const char *shell; /* user shell to launch notif. cmd */ + unsigned notify_all; /* notify all appointments */ + pthread_mutex_t mutex; }; /* Available types of items. */ @@ -478,7 +499,6 @@ enum item_type { enum eraseflg { ERASE_DONT_FORCE, ERASE_FORCE, - ERASE_FORCE_KEEP_NOTE, ERASE_FORCE_ONLY_NOTE, ERASE_CUT }; @@ -486,8 +506,8 @@ enum eraseflg { /* Return codes for the getstring() function. */ enum getstr { GETSTRING_VALID, - GETSTRING_ESC, /* user pressed escape to cancel editing. */ - GETSTRING_RET /* return was pressed without entering any text. */ + GETSTRING_ESC, /* user pressed escape to cancel editing. */ + GETSTRING_RET /* return was pressed without entering any text. */ }; /* Week days. */ @@ -548,380 +568,429 @@ enum save_display { /* apoint.c */ extern llist_ts_t alist_p; -void apoint_free_bkp (enum eraseflg); -void apoint_llist_init (void); -void apoint_llist_free (void); -void apoint_hilt_set (int); -void apoint_hilt_decrease (void); -void apoint_hilt_increase (void); -int apoint_hilt (void); -struct apoint *apoint_new (char *, char *, long, long, char); -void apoint_add (void); -void apoint_delete (struct conf *, unsigned *, unsigned *); -int apoint_cut (unsigned *, unsigned *); -void apoint_paste (unsigned *, unsigned *, int); -unsigned apoint_inday (struct apoint *, long); -void apoint_sec2str (struct apoint *, int, 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_scroll_pad_down (int, int); -void apoint_scroll_pad_up (int); -struct notify_app *apoint_check_next (struct notify_app *, long); -struct apoint *apoint_recur_s2apoint_s (struct recur_apoint *); -void apoint_switch_notify (void); -void apoint_update_panel (int); -void apoint_paste_item (void); +void apoint_free_bkp(void); +void apoint_llist_init(void); +void apoint_llist_free(void); +void apoint_hilt_set(int); +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); +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_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_update_panel(int); +void apoint_paste_item(void); /* args.c */ -int parse_args (int, char **, struct conf *); +int parse_args(int, char **); /* calendar.c */ -void calendar_view_next (void); -void calendar_view_prev (void); -void calendar_set_view (int); -int calendar_get_view (void); -void calendar_start_date_thread (void); -void calendar_stop_date_thread (void); -void calendar_set_current_date (void); -void calendar_set_first_day_of_week (enum wday); -void calendar_change_first_day_of_week (void); -unsigned calendar_week_begins_on_monday (void); -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_update_panel (struct window *); -void calendar_goto_today (void); -void calendar_change_day (int); -void calendar_move (enum move); -long calendar_start_of_year (void); -long calendar_end_of_year (void); -char *calendar_get_pom (time_t); +void calendar_view_next(void); +void calendar_view_prev(void); +void calendar_set_view(int); +int calendar_get_view(void); +void calendar_start_date_thread(void); +void calendar_stop_date_thread(void); +void calendar_set_current_date(void); +void calendar_set_first_day_of_week(enum wday); +void calendar_change_first_day_of_week(void); +unsigned calendar_week_begins_on_monday(void); +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_update_panel(struct window *); +void calendar_goto_today(void); +void calendar_change_day(int); +void calendar_move(enum move, int); +long calendar_start_of_year(void); +long calendar_end_of_year(void); +const char *calendar_get_pom(time_t); + +/* config.c */ + +void config_load(void); +unsigned config_save(void); /* custom.c */ -void custom_init_attr (void); -void custom_apply_attr (WINDOW *, int); -void custom_remove_attr (WINDOW *, int); -void custom_load_conf (struct conf *, int); -void custom_config_bar (void); -void custom_layout_config (void); -void custom_sidebar_config (void); -void custom_color_config (void); -void custom_color_theme_name (char *); -void custom_confwin_init (struct window *, char *); -void custom_set_swsiz (struct scrollwin *); -void custom_general_config (struct conf *); -void custom_keys_config (void); +void custom_init_attr(void); +void custom_apply_attr(WINDOW *, int); +void custom_remove_attr(WINDOW *, int); +void custom_config_bar(void); +void custom_layout_config(void); +void custom_sidebar_config(void); +void custom_color_config(void); +void custom_color_theme_name(char *); +void custom_confwin_init(struct window *, const char *); +void custom_set_swsiz(struct scrollwin *); +void custom_general_config(void); +void custom_keys_config(void); +void custom_config_main(void); /* day.c */ -void day_free_list (void); -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); -int day_check_if_item (struct date); -unsigned day_chk_busy_slices (struct date, int, int *); -void day_edit_item (struct conf *); -int day_erase_item (long, int, enum eraseflg); -int day_cut_item (long, int); -int day_paste_item (long, int); -struct day_item *day_get_item (int); -int day_item_nb (long, int, int); -void day_edit_note (char *); -void day_view_note (char *); +void day_free_list(void); +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); +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_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); /* dmon.c */ -void dmon_start (int); -void dmon_stop (void); +void dmon_start(int); +void dmon_stop(void); /* event.c */ extern llist_t eventlist; -void event_free_bkp (enum eraseflg); -void event_llist_init (void); -void event_llist_free (void); -struct event *event_new (char *, char *, long, int); -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_free_bkp(void); +void event_llist_init(void); +void event_llist_free(void); +struct event *event_new(char *, char *, long, int); +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); /* help.c */ -void help_wins_init (struct scrollwin *, int, int, int, int); -void help_screen (void); +void help_wins_init(struct scrollwin *, int, int, int, int); +void help_screen(void); + +/* getstring.c */ +enum getstr getstring(WINDOW *, char *, int, int, int); +int updatestring(WINDOW *, char **, int, int); + +/* ical.c */ +void ical_import_data(FILE *, FILE *, unsigned *, unsigned *, unsigned *, + unsigned *, unsigned *); +void ical_export_data(FILE *); /* io.c */ -unsigned io_fprintln (const char *, const char *, ...); -void io_init (char *, char *); -void io_extract_data (char *, const char *, int); -unsigned io_save_conf (struct conf *); -unsigned io_save_apts (void); -unsigned io_save_todo (void); -unsigned io_save_keys (void); -void io_save_cal (struct conf *, enum save_display); -void io_load_app (void); -void io_load_todo (void); -void io_load_keys (char *); -void io_check_dir (char *, int *); -unsigned io_file_exist (char *); -void io_check_file (char *, int *); -int io_check_data_files (void); -void io_startup_screen (unsigned, int); -void io_export_data (enum export_type, struct conf *); -void io_export_bar (void); -void io_import_data (enum import_type, struct conf *, char *); -struct io_file *io_log_init (void); -void io_log_print (struct io_file *, int, char *); -void io_log_display (struct io_file *, char *, char *); -void io_log_free (struct io_file *); -void io_start_psave_thread (struct conf *); -void io_stop_psave_thread (void); -void io_set_lock (void); -unsigned io_dump_pid (char *); -unsigned io_get_pid (char *); -int io_file_is_empty (char *); +unsigned io_fprintln(const char *, const char *, ...); +void io_init(const char *, const char *); +void io_extract_data(char *, const char *, int); +unsigned io_save_apts(void); +unsigned io_save_todo(void); +unsigned io_save_keys(void); +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_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 *); +void io_log_display(struct io_file *, const char *, const char *); +void io_log_free(struct io_file *); +void io_start_psave_thread(void); +void io_stop_psave_thread(void); +void io_set_lock(void); +unsigned io_dump_pid(char *); +unsigned io_get_pid(char *); +int io_file_is_empty(char *); +int io_file_cp(const char *, const char *); /* keys.c */ -void keys_init (void); -void keys_free (void); -void keys_dump_defaults (char *); -char *keys_get_label (enum key); -enum key keys_get_action (int); -enum key keys_getch (WINDOW *win); -int keys_assign_binding (int, enum key); -void keys_remove_binding (int, enum key); -int keys_str2int (char *); -char *keys_int2str (int); -int keys_action_count_keys (enum key); -char *keys_action_firstkey (enum key); -char *keys_action_nkey (enum key, int); -char *keys_action_allkeys (enum key); -void keys_display_bindings_bar (WINDOW *, struct binding **, int, int); -void keys_popup_info (enum key); -void keys_save_bindings (FILE *); -int keys_check_missing_bindings (void); -void keys_fill_missing (void); +void keys_init(void); +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 *); +int keys_assign_binding(int, enum key); +void keys_remove_binding(int, enum key); +int keys_str2int(const char *); +const char *keys_int2str(int); +int keys_action_count_keys(enum key); +const char *keys_action_firstkey(enum key); +const char *keys_action_nkey(enum key, int); +char *keys_action_allkeys(enum key); +void keys_display_bindings_bar(WINDOW *, struct binding *[], int, int, + int, struct binding *); +void keys_popup_info(enum key); +void keys_save_bindings(FILE *); +int keys_check_missing_bindings(void); +void keys_fill_missing(void); /* mem.c */ -void *xmalloc (size_t); -void *xcalloc (size_t, size_t); -void *xrealloc (void *, size_t, size_t); -char *xstrdup (const char *); -void xfree (void *); +void *xmalloc(size_t); +void *xcalloc(size_t, size_t); +void *xrealloc(void *, size_t, size_t); +char *xstrdup(const char *); +void xfree(void *); #ifdef CALCURSE_MEMORY_DEBUG -# define mem_malloc(s) dbg_malloc ((s), __FILE_POS__) -# define mem_calloc(n, s) dbg_calloc ((n), (s), __FILE_POS__) -# define mem_realloc(p, n, s) dbg_realloc ((p), (n), (s), __FILE_POS__) -# define mem_strdup(s) dbg_strdup ((s), __FILE_POS__) -# define mem_free(p) dbg_free ((p), __FILE_POS__) +#define mem_malloc(s) dbg_malloc ((s), __FILE_POS__) +#define mem_calloc(n, s) dbg_calloc ((n), (s), __FILE_POS__) +#define mem_realloc(p, n, s) dbg_realloc ((p), (n), (s), __FILE_POS__) +#define mem_strdup(s) dbg_strdup ((s), __FILE_POS__) +#define mem_free(p) dbg_free ((p), __FILE_POS__) -void *dbg_malloc (size_t, const char *); -void *dbg_calloc (size_t, size_t, const char *); -void *dbg_realloc (void *, size_t, size_t, const char *); -char *dbg_strdup (const char *, const char *); -void dbg_free (void *, const char *); -void mem_stats (void); +void *dbg_malloc(size_t, const char *); +void *dbg_calloc(size_t, size_t, const char *); +void *dbg_realloc(void *, size_t, size_t, const char *); +char *dbg_strdup(const char *, const char *); +void dbg_free(void *, const char *); +void mem_stats(void); #else /* MEMORY DEBUG disabled */ -# define mem_malloc(s) xmalloc ((s)) -# define mem_calloc(n, s) xcalloc ((n), (s)) -# define mem_realloc(p, n, s) xrealloc ((p), (n), (s)) -# define mem_strdup(s) xstrdup ((s)) -# define mem_free(p) xfree ((p)) -# define mem_stats() +#define mem_malloc(s) xmalloc ((s)) +#define mem_calloc(n, s) xcalloc ((n), (s)) +#define mem_realloc(p, n, s) xrealloc ((p), (n), (s)) +#define mem_strdup(s) xstrdup ((s)) +#define mem_free(p) xfree ((p)) +#define mem_stats() #endif /* CALCURSE_MEMORY_DEBUG */ +/* note.c */ +char *generate_note(const char *); +void edit_note(char **, const char *); +void view_note(const char *, const char *); +void erase_note(char **); +void note_read(char *, FILE *); +void note_gc(void); + /* notify.c */ -int notify_time_left (void); -unsigned notify_needs_reminder (void); -void notify_update_app (long, char, char *); -int notify_bar (void); -void notify_init_vars (void); -void notify_init_bar (void); -void notify_free_app (void); -void notify_start_main_thread (void); -void notify_stop_main_thread (void); -void notify_reinit_bar (void); -unsigned notify_launch_cmd (void); -void notify_update_bar (void); -unsigned notify_get_next (struct notify_app *); -unsigned notify_get_next_bkgd (void); -char *notify_app_txt (void); -void notify_check_next_app (int); -void notify_check_added (char *, long, char); -void notify_check_repeated (struct recur_apoint *); -int notify_same_item (long); -int notify_same_recur_item (struct recur_apoint *); -void notify_config_bar (void); +int notify_time_left(void); +unsigned notify_needs_reminder(void); +void notify_update_app(long, char, char *); +int notify_bar(void); +void notify_init_vars(void); +void notify_init_bar(void); +void notify_free_app(void); +void notify_start_main_thread(void); +void notify_stop_main_thread(void); +void notify_reinit_bar(void); +unsigned notify_launch_cmd(void); +void notify_update_bar(void); +unsigned notify_get_next(struct notify_app *); +unsigned notify_get_next_bkgd(void); +char *notify_app_txt(void); +void notify_check_next_app(int); +void notify_check_added(char *, long, char); +void notify_check_repeated(struct recur_apoint *); +int notify_same_item(long); +int notify_same_recur_item(struct recur_apoint *); +void notify_config_bar(void); + +/* pcal.c */ +void pcal_export_data(FILE *); /* recur.c */ extern llist_ts_t recur_alist_p; extern llist_t recur_elist; -void recur_event_free_bkp (enum eraseflg); -void recur_apoint_free_bkp (enum eraseflg); -void recur_apoint_llist_init (void); -void recur_apoint_llist_free (void); -void recur_event_llist_free (void); -struct recur_apoint *recur_apoint_new (char *, char *, long, long, char, - int, int, long, llist_t *); -struct recur_event *recur_event_new (char *, char *, long, int, int, int, - long, llist_t *); -char recur_def2char (enum recur_type); -int recur_char2def (char); -struct recur_apoint *recur_apoint_scan (FILE *, struct tm, struct tm, - char, int, struct tm, char *, - llist_t *, char); -struct recur_event *recur_event_scan (FILE *, struct tm, int, char, - int, struct tm, char *, - llist_t *); -void recur_save_data (FILE *); -unsigned recur_item_inday (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 (struct conf *); -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_event_free_bkp(void); +void recur_apoint_free_bkp(void); +void recur_apoint_llist_init(void); +void recur_apoint_llist_free(void); +void recur_event_llist_free(void); +struct recur_apoint *recur_apoint_new(char *, char *, long, long, char, + int, int, long, llist_t *); +struct recur_event *recur_event_new(char *, char *, long, int, int, int, + long, llist_t *); +char recur_def2char(enum recur_type); +int recur_char2def(char); +struct recur_apoint *recur_apoint_scan(FILE *, struct tm, struct tm, + char, int, struct tm, char *, + llist_t *, char); +struct recur_event *recur_event_scan(FILE *, struct tm, int, char, + int, struct tm, char *, llist_t *); +void recur_apoint_write(struct recur_apoint *, FILE *); +void recur_event_write(struct recur_event *, FILE *); +void recur_save_data(FILE *); +unsigned recur_item_find_occurrence(long, long, llist_t *, int, + int, long, long, unsigned *); +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); +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); /* sigs.c */ -void sigs_init (void); -unsigned sigs_set_hdlr (int, void (*)(int)); +void sigs_init(void); +unsigned sigs_set_hdlr(int, void (*)(int)); /* todo.c */ extern llist_t todolist; -void todo_hilt_set (int); -void todo_hilt_decrease (void); -void todo_hilt_increase (void); -int todo_hilt (void); -int todo_nb (void); -void todo_set_nb (int); -void todo_set_first (int); -void todo_first_increase (void); -void todo_first_decrease (void); -int todo_hilt_pos (void); -char *todo_saved_mesg (void); -void todo_new_item (void); -struct todo *todo_add (char *, int, char *); -void todo_flag (void); -void todo_delete (struct conf *); -void todo_chg_priority (int); -void todo_edit_item (void); -void todo_update_panel (int); -void todo_edit_note (char *); -void todo_view_note (char *); -void todo_init_list (void); -void todo_free_list (void); +void todo_hilt_set(int); +void todo_hilt_decrease(int); +void todo_hilt_increase(int); +int todo_hilt(void); +int todo_nb(void); +void todo_set_nb(int); +void todo_set_first(int); +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_update_panel(int); +void todo_edit_note(const char *); +void todo_view_note(const char *); +void todo_pipe_item(void); +void todo_init_list(void); +void todo_free_list(void); + +/* utf8.c */ +int utf8_width(char *); +int utf8_strwidth(char *); /* utils.c */ -void exit_calcurse (int) __attribute__((__noreturn__)); -void free_user_data (void); -void fatalbox (const char *); -void warnbox (const char *); -void status_mesg (char *, char *); -void erase_window_part (WINDOW *, int, int, int, int); -WINDOW *popup (int, int, int, int, char *, char *, int); -void print_in_middle (WINDOW *, int, int, int, char *); -enum getstr getstring (WINDOW *, char *, int, int, int); -int updatestring (WINDOW *, char **, int, int); -int is_all_digit (char *); -long get_item_time (long); -int get_item_hour (long); -int get_item_min (long); -long date2sec (struct date, unsigned, unsigned); -char *date_sec2date_str (long, char *); -void date_sec2date_fmt (long, const char *, char *); -long date_sec_change (long, int, int); -long update_time_in_date (long, unsigned, unsigned); -long get_sec_date (struct date); -long min2sec (unsigned); -int check_time (char *); -void draw_scrollbar (WINDOW *, int, int, int, int, int, unsigned); -void item_in_popup (char *, char *, char *, char *); -long get_today (void); -long now (void); -char *nowstr (void); -long mystrtol (const char *); -void print_bool_option_incolor (WINDOW *, unsigned, int, int); -const char *get_tempdir (void); -char *new_tempfile (const char *, int); -void erase_note (char **, enum eraseflg); -int parse_date (char *, enum datefmt, int *, int *, int *, - struct date *); -void str_toupper (char *); -void file_close (FILE *, const char *); -void psleep (unsigned); +void exit_calcurse(int) __attribute__ ((__noreturn__)); +void free_user_data(void); +void fatalbox(const char *); +void warnbox(const char *); +void status_mesg(const char *, const char *); +int status_ask_choice(const char *, const char[], int); +int status_ask_bool(const char *); +int status_ask_simplechoice(const char *, const char *[], int); +void erase_window_part(WINDOW *, int, int, int, int); +WINDOW *popup(int, int, int, int, const char *, const char *, int); +void print_in_middle(WINDOW *, int, int, int, const char *); +int is_all_digit(const char *); +long get_item_time(long); +int get_item_hour(long); +int get_item_min(long); +long date2sec(struct date, unsigned, unsigned); +char *date_sec2date_str(long, const char *); +void date_sec2date_fmt(long, const char *, char *); +long date_sec_change(long, int, int); +long update_time_in_date(long, unsigned, unsigned); +long get_sec_date(struct date); +long min2sec(unsigned); +void draw_scrollbar(WINDOW *, int, int, int, int, int, unsigned); +void item_in_popup(const char *, const char *, const char *, const char *); +long get_today(void); +long now(void); +char *nowstr(void); +long mystrtol(const char *); +void print_bool_option_incolor(WINDOW *, unsigned, int, int); +const char *get_tempdir(void); +char *new_tempfile(const char *, int); +int parse_date(const char *, enum datefmt, int *, int *, int *, struct date *); +int parse_time(const char *, unsigned *, unsigned *); +int parse_duration(const char *, unsigned *); +void str_toupper(char *); +void file_close(FILE *, const char *); +void psleep(unsigned); +int fork_exec(int *, int *, const char *, const char *const *); +int shell_exec(int *, int *, const char *, const char *const *); +int child_wait(int *, int *, int); +void press_any_key(void); +void print_apoint(const char *, long, struct apoint *); +void print_event(const char *, long, struct event *); +void print_recur_apoint(const char *, long, unsigned, struct recur_apoint *); +void print_recur_event(const char *, long, struct recur_event *); +void print_todo(const char *, struct todo *); /* vars.c */ -extern int col, row; -extern int resize; -extern unsigned colorize; -extern enum ui_mode ui_mode; -extern int days[12]; -extern char *monthnames[12]; -extern char *daynames[8]; -extern char path_dir[BUFSIZ]; -extern char path_todo[BUFSIZ]; -extern char path_apts[BUFSIZ]; -extern char path_conf[BUFSIZ]; -extern char path_keys[BUFSIZ]; -extern char path_notes[BUFSIZ]; -extern char path_cpid[BUFSIZ]; -extern char path_dpid[BUFSIZ]; -extern char path_dmon_log[BUFSIZ]; -extern struct pad apad; -extern struct nbar nbar; -extern struct dmon_conf dmon; -void vars_init (struct conf *); +extern int col, row; +extern int resize; +extern unsigned colorize; +extern int foreground, background; +extern enum ui_mode ui_mode; +extern int read_only; +extern int days[12]; +extern const char *monthnames[12]; +extern const char *daynames[8]; +extern char path_dir[BUFSIZ]; +extern char path_todo[BUFSIZ]; +extern char path_apts[BUFSIZ]; +extern char path_conf[BUFSIZ]; +extern char path_keys[BUFSIZ]; +extern char path_notes[BUFSIZ]; +extern char path_cpid[BUFSIZ]; +extern char path_dpid[BUFSIZ]; +extern char path_dmon_log[BUFSIZ]; +extern struct conf conf; +extern struct pad apad; +extern struct nbar nbar; +extern struct dmon_conf dmon; +void vars_init(void); /* wins.c */ extern struct window win[NBWINS]; -int wins_refresh (void); -int wins_wrefresh (WINDOW *); -int wins_doupdate (void); -int wins_layout (void); -void wins_set_layout (int); -unsigned wins_sbar_width (void); -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); -void wins_init (void); -void wins_scrollwin_init (struct scrollwin *); -void wins_scrollwin_delete (struct scrollwin *); -void wins_scrollwin_display (struct scrollwin *); -void wins_scrollwin_up (struct scrollwin *, int); -void wins_scrollwin_down (struct scrollwin *, int); -void wins_reinit (void); -void wins_reinit_panels (void); -void wins_show (WINDOW *, char *); -void wins_get_config (void); -void wins_update_border (void); -void wins_update_panels (void); -void wins_update (void); -void wins_reset (void); -void wins_launch_external (const char *, const char *); -void wins_status_bar (void); -void wins_erase_status_bar (void); -void wins_other_status_page (int); -void wins_reset_status_page (void); +int wins_refresh(void); +int wins_wrefresh(WINDOW *); +int wins_doupdate(void); +int wins_layout(void); +void wins_set_layout(int); +unsigned wins_sbar_width(void); +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); +void wins_init(void); +void wins_scrollwin_init(struct scrollwin *); +void wins_scrollwin_delete(struct scrollwin *); +void wins_scrollwin_display(struct scrollwin *); +void wins_scrollwin_up(struct scrollwin *, int); +void wins_scrollwin_down(struct scrollwin *, int); +void wins_reinit(void); +void wins_reinit_panels(void); +void wins_show(WINDOW *, const char *); +void wins_get_config(void); +void wins_update_border(int); +void wins_update_panels(int); +void wins_update(int); +void wins_reset(void); +void wins_prepare_external(void); +void wins_unprepare_external(void); +void wins_launch_external(const char *, const char *); +void wins_status_bar(void); +void wins_erase_status_bar(void); +void wins_other_status_page(int); +void wins_reset_status_page(void); #endif /* CALCURSE_H */ diff --git a/src/calendar.c b/src/calendar.c index e303ab9..7328718 100644 --- a/src/calendar.c +++ b/src/calendar.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -48,12 +48,12 @@ #endif #define EPOCH 90 -#define EPSILONg 279.403303 /* solar ecliptic long at EPOCH */ -#define RHOg 282.768422 /* solar ecliptic long of perigee at EPOCH */ -#define ECCEN 0.016713 /* solar orbit eccentricity */ -#define lzero 318.351648 /* lunar mean long at EPOCH */ -#define Pzero 36.340410 /* lunar mean long of perigee at EPOCH */ -#define Nzero 318.510107 /* lunar mean long of node at EPOCH */ +#define EPSILONg 279.403303 /* solar ecliptic long at EPOCH */ +#define RHOg 282.768422 /* solar ecliptic long of perigee at EPOCH */ +#define ECCEN 0.016713 /* solar orbit eccentricity */ +#define lzero 318.351648 /* lunar mean long at EPOCH */ +#define Pzero 36.340410 /* lunar mean long of perigee at EPOCH */ +#define Nzero 318.510107 /* lunar mean long of node at EPOCH */ #define ISLEAP(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) @@ -77,208 +77,184 @@ static unsigned calendar_view, week_begins_on_monday; static pthread_mutex_t date_thread_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_t calendar_t_date; -static void draw_monthly_view (struct window *, struct date *, unsigned); -static void draw_weekly_view (struct window *, struct date *, unsigned); +static void draw_monthly_view(struct window *, struct date *, unsigned); +static void draw_weekly_view(struct window *, struct date *, unsigned); static void (*draw_calendar[CAL_VIEWS]) (struct window *, struct date *, - unsigned) = - {draw_monthly_view, draw_weekly_view}; + unsigned) = { +draw_monthly_view, draw_weekly_view}; /* Switch between calendar views (monthly view is selected by default). */ -void -calendar_view_next (void) +void calendar_view_next(void) { calendar_view++; if (calendar_view == CAL_VIEWS) calendar_view = 0; } -void -calendar_view_prev (void) +void calendar_view_prev(void) { if (calendar_view == 0) calendar_view = CAL_VIEWS; calendar_view--; } -void -calendar_set_view (int view) +void calendar_set_view(int view) { calendar_view = (view < 0 || view >= CAL_VIEWS) ? CAL_MONTH_VIEW : view; } -int -calendar_get_view (void) +int calendar_get_view(void) { return (int)calendar_view; } /* Thread needed to update current date in calendar. */ /* ARGSUSED0 */ -static void * -calendar_date_thread (void *arg) +static void *calendar_date_thread(void *arg) { time_t actual, tomorrow; - for (;;) - { - tomorrow = (time_t) (get_today () + DAYINSEC); + for (;;) { + tomorrow = (time_t) (get_today() + DAYINSEC); - while ((actual = time (NULL)) < tomorrow) - (void)sleep (tomorrow - actual); + while ((actual = time(NULL)) < tomorrow) + sleep(tomorrow - actual); - calendar_set_current_date (); - calendar_update_panel (&win[CAL]); - } + calendar_set_current_date(); + calendar_update_panel(&win[CAL]); + } - return (void *)0; + return NULL; } /* Launch the calendar date thread. */ -void -calendar_start_date_thread (void) +void calendar_start_date_thread(void) { - pthread_create (&calendar_t_date, NULL, calendar_date_thread, NULL); + pthread_create(&calendar_t_date, NULL, calendar_date_thread, NULL); } /* Stop the calendar date thread. */ -void -calendar_stop_date_thread (void) +void calendar_stop_date_thread(void) { - if (calendar_t_date) - { - pthread_cancel (calendar_t_date); - pthread_join (calendar_t_date, NULL); - } + if (calendar_t_date) { + pthread_cancel(calendar_t_date); + pthread_join(calendar_t_date, NULL); + } } /* Set static variable today to current date */ -void -calendar_set_current_date (void) +void calendar_set_current_date(void) { time_t timer; struct tm *tm; - timer = time (NULL); - tm = localtime (&timer); + timer = time(NULL); + tm = localtime(&timer); - pthread_mutex_lock (&date_thread_mutex); + pthread_mutex_lock(&date_thread_mutex); today.dd = tm->tm_mday; today.mm = tm->tm_mon + 1; today.yyyy = tm->tm_year + 1900; - pthread_mutex_unlock (&date_thread_mutex); + pthread_mutex_unlock(&date_thread_mutex); } /* Needed to display sunday or monday as the first day of week in calendar. */ -void -calendar_set_first_day_of_week (enum wday first_day) -{ - switch (first_day) - { - case SUNDAY: - week_begins_on_monday = 0; - break; - case MONDAY: - week_begins_on_monday = 1; - break; - default: - ERROR_MSG (_("ERROR setting first day of week")); - week_begins_on_monday = 0; - /* NOTREACHED */ - } +void calendar_set_first_day_of_week(enum wday first_day) +{ + switch (first_day) { + case SUNDAY: + week_begins_on_monday = 0; + break; + case MONDAY: + week_begins_on_monday = 1; + break; + default: + ERROR_MSG(_("ERROR setting first day of week")); + week_begins_on_monday = 0; + /* NOTREACHED */ + } } /* Swap first day of week in calendar. */ -void -calendar_change_first_day_of_week (void) +void calendar_change_first_day_of_week(void) { week_begins_on_monday = !week_begins_on_monday; } /* Return 1 if week begins on monday, 0 otherwise. */ -unsigned -calendar_week_begins_on_monday (void) +unsigned calendar_week_begins_on_monday(void) { - return (week_begins_on_monday); + return week_begins_on_monday; } /* Fill in the given variable with the current date. */ -void -calendar_store_current_date (struct date *date) +void calendar_store_current_date(struct date *date) { - pthread_mutex_lock (&date_thread_mutex); + pthread_mutex_lock(&date_thread_mutex); *date = today; - pthread_mutex_unlock (&date_thread_mutex); + pthread_mutex_unlock(&date_thread_mutex); } /* This is to start at the current date in calendar. */ -void -calendar_init_slctd_day (void) +void calendar_init_slctd_day(void) { - calendar_store_current_date (&slctd_day); + calendar_store_current_date(&slctd_day); } /* Return the selected day in calendar */ -struct date * -calendar_get_slctd_day (void) +struct date *calendar_get_slctd_day(void) { - return (&slctd_day); + return &slctd_day; } /* Returned value represents the selected day in calendar (in seconds) */ -long -calendar_get_slctd_day_sec (void) +long calendar_get_slctd_day_sec(void) { - return (date2sec (slctd_day, 0, 0)); + return date2sec(slctd_day, 0, 0); } -static int -calendar_get_wday (struct date *date) +static int calendar_get_wday(struct date *date) { struct tm t; - (void)memset (&t, 0, sizeof (struct tm)); + memset(&t, 0, sizeof(struct tm)); t.tm_mday = date->dd; t.tm_mon = date->mm - 1; t.tm_year = date->yyyy - 1900; - (void)mktime (&t); + mktime(&t); return t.tm_wday; } -static unsigned -months_to_days (unsigned month) +static unsigned months_to_days(unsigned month) { - return ((month * 3057 - 3007) / 100); + return (month * 3057 - 3007) / 100; } - -static long -years_to_days (unsigned year) +static long years_to_days(unsigned year) { - return (year * 365L + year / 4 - year / 100 + year / 400); + return year * 365L + year / 4 - year / 100 + year / 400; } -static long -ymd_to_scalar (unsigned year, unsigned month, unsigned day) +static long ymd_to_scalar(unsigned year, unsigned month, unsigned day) { long scalar; - scalar = day + months_to_days (month); + scalar = day + months_to_days(month); if (month > 2) - scalar -= ISLEAP (year) ? 1 : 2; + scalar -= ISLEAP(year) ? 1 : 2; year--; - scalar += years_to_days (year); + scalar += years_to_days(year); - return (scalar); + return scalar; } /* * Used to change date by adding a certain amount of days or weeks. * Returns 0 on success, 1 otherwise. */ -static int -date_change (struct tm *date, int delta_month, int delta_day) +static int date_change(struct tm *date, int delta_month, int delta_day) { struct tm t; @@ -286,19 +262,18 @@ date_change (struct tm *date, int delta_month, int delta_day) t.tm_mon += delta_month; t.tm_mday += delta_day; - if (mktime (&t) == -1) - return (1); - else - { - *date = t; - return (0); - } + if (mktime(&t) == -1) + return 1; + else { + *date = t; + return 0; + } } /* Draw the monthly view inside calendar panel. */ static void -draw_monthly_view (struct window *cwin, struct date *current_day, - unsigned sunday_first) +draw_monthly_view(struct window *cwin, struct date *current_day, + unsigned sunday_first) { const int OFFY = 2 + (CALHEIGHT - 9) / 2; struct date check_day; @@ -311,106 +286,92 @@ draw_monthly_view (struct window *cwin, struct date *current_day, yr = slctd_day.yyyy; /* offset for centering calendar in window */ - SBAR_WIDTH = wins_sbar_width (); + SBAR_WIDTH = wins_sbar_width(); OFFX = (SBAR_WIDTH - 27) / 2; ofs_y = OFFY; ofs_x = OFFX; /* checking the number of days in february */ numdays = days[mo - 1]; - if (2 == mo && ISLEAP (yr)) + if (2 == mo && ISLEAP(yr)) ++numdays; /* * the first calendar day will be monday or sunday, depending on * 'week_begins_on_monday' value */ - c_day_1 = (int) ((ymd_to_scalar (yr, mo, 1 + sunday_first) - (long) 1) % 7L); + c_day_1 = (int)((ymd_to_scalar(yr, mo, 1 + sunday_first) - (long)1) % 7L); /* Write the current month and year on top of the calendar */ - custom_apply_attr (cwin->p, ATTR_HIGHEST); - mvwprintw (cwin->p, ofs_y, - (SBAR_WIDTH - (strlen (_(monthnames[mo - 1])) + 5)) / 2, - "%s %d", _(monthnames[mo - 1]), slctd_day.yyyy); - custom_remove_attr (cwin->p, ATTR_HIGHEST); + custom_apply_attr(cwin->p, ATTR_HIGHEST); + mvwprintw(cwin->p, ofs_y, + (SBAR_WIDTH - (strlen(_(monthnames[mo - 1])) + 5)) / 2, + "%s %d", _(monthnames[mo - 1]), slctd_day.yyyy); + custom_remove_attr(cwin->p, ATTR_HIGHEST); ++ofs_y; /* print the days, with regards to the first day of the week */ - custom_apply_attr (cwin->p, ATTR_HIGHEST); - for (j = 0; j < WEEKINDAYS; j++) - { - mvwprintw (cwin->p, ofs_y, ofs_x + 4 * j, "%s", - _(daynames[1 + j - sunday_first])); - } - custom_remove_attr (cwin->p, ATTR_HIGHEST); + custom_apply_attr(cwin->p, ATTR_HIGHEST); + for (j = 0; j < WEEKINDAYS; j++) { + mvwprintw(cwin->p, ofs_y, ofs_x + 4 * j, "%s", + _(daynames[1 + j - sunday_first])); + } + custom_remove_attr(cwin->p, ATTR_HIGHEST); day_1_sav = (c_day_1 + 1) * 3 + c_day_1 - 7; - 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); + 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; - /* Go to next line, the week is over. */ - if (!c_day_1 && 1 != c_day) - { - ofs_y++; - ofs_x = OFFX - day_1_sav - 4 * c_day; - } + /* check if the day contains an event or an appointment */ + item_this_day = day_check_if_item(check_day); - /* This is today, so print it in yellow. */ - if (c_day == current_day->dd - && current_day->mm == slctd_day.mm - && current_day->yyyy == slctd_day.yyyy - && current_day->dd != slctd_day.dd) - { - custom_apply_attr (cwin->p, ATTR_LOWEST); - mvwprintw (cwin->p, ofs_y + 1, - ofs_x + day_1_sav + 4 * c_day + 1, "%2d", c_day); - custom_remove_attr (cwin->p, ATTR_LOWEST); - } - else if (c_day == slctd_day.dd) - { - /* This is the selected day, print it according to user's theme. */ - custom_apply_attr (cwin->p, ATTR_HIGHEST); - mvwprintw (cwin->p, ofs_y + 1, - ofs_x + day_1_sav + 4 * c_day + 1, "%2d", - c_day); - custom_remove_attr (cwin->p, ATTR_HIGHEST); - } - else if (item_this_day) - { - custom_apply_attr (cwin->p, ATTR_LOW); - mvwprintw (cwin->p, ofs_y + 1, - ofs_x + day_1_sav + 4 * c_day + 1, "%2d", - c_day); - custom_remove_attr (cwin->p, ATTR_LOW); - } - else - /* otherwise, print normal days in black */ - mvwprintw (cwin->p, ofs_y + 1, - ofs_x + day_1_sav + 4 * c_day + 1, "%2d", - c_day); + /* Go to next line, the week is over. */ + if (!c_day_1 && 1 != c_day) { + ofs_y++; + ofs_x = OFFX - day_1_sav - 4 * c_day; } -} -static int -weeknum (const struct tm *t, int firstweekday) + /* This is today, so print it in yellow. */ + if (c_day == current_day->dd + && current_day->mm == slctd_day.mm + && current_day->yyyy == slctd_day.yyyy + && current_day->dd != slctd_day.dd) { + custom_apply_attr(cwin->p, ATTR_LOWEST); + mvwprintw(cwin->p, ofs_y + 1, + ofs_x + day_1_sav + 4 * c_day + 1, "%2d", c_day); + custom_remove_attr(cwin->p, ATTR_LOWEST); + } else if (c_day == slctd_day.dd) { + /* This is the selected day, print it according to user's theme. */ + custom_apply_attr(cwin->p, ATTR_HIGHEST); + mvwprintw(cwin->p, ofs_y + 1, + ofs_x + day_1_sav + 4 * c_day + 1, "%2d", c_day); + custom_remove_attr(cwin->p, ATTR_HIGHEST); + } else if (item_this_day) { + custom_apply_attr(cwin->p, ATTR_LOW); + mvwprintw(cwin->p, ofs_y + 1, + ofs_x + day_1_sav + 4 * c_day + 1, "%2d", c_day); + custom_remove_attr(cwin->p, ATTR_LOW); + } else + /* otherwise, print normal days in black */ + mvwprintw(cwin->p, ofs_y + 1, + ofs_x + day_1_sav + 4 * c_day + 1, "%2d", c_day); + } +} + +static int weeknum(const struct tm *t, int firstweekday) { int wday, wnum; wday = t->tm_wday; - if (firstweekday == MONDAY) - { - if (wday == SUNDAY) - wday = 6; - else - wday--; - } + if (firstweekday == MONDAY) { + if (wday == SUNDAY) + wday = 6; + else + wday--; + } wnum = ((t->tm_yday + WEEKINDAYS - wday) / WEEKINDAYS); if (wnum < 0) wnum = 0; @@ -421,64 +382,60 @@ weeknum (const struct tm *t, int firstweekday) /* * Compute the week number according to ISO 8601. */ -static int -ISO8601weeknum (const struct tm *t) +static int ISO8601weeknum(const struct tm *t) { int wnum, jan1day; - wnum = weeknum (t, MONDAY); + wnum = weeknum(t, MONDAY); jan1day = t->tm_wday - (t->tm_yday % WEEKINDAYS); if (jan1day < 0) jan1day += WEEKINDAYS; - switch (jan1day) - { - case MONDAY: - break; - case TUESDAY: - case WEDNESDAY: - case THURSDAY: - wnum++; - break; - case FRIDAY: - case SATURDAY: - case SUNDAY: - if (wnum == 0) - { - /* Get week number of last week of last year. */ - struct tm dec31ly; /* 12/31 last year */ - - dec31ly = *t; - dec31ly.tm_year--; - dec31ly.tm_mon = 11; - dec31ly.tm_mday = 31; - dec31ly.tm_wday = (jan1day == SUNDAY) ? 6 : jan1day - 1; - dec31ly.tm_yday = 364 + ISLEAP (dec31ly.tm_year + 1900); - wnum = ISO8601weeknum (&dec31ly); - } - break; + switch (jan1day) { + case MONDAY: + break; + case TUESDAY: + case WEDNESDAY: + case THURSDAY: + wnum++; + break; + case FRIDAY: + case SATURDAY: + case SUNDAY: + if (wnum == 0) { + /* Get week number of last week of last year. */ + struct tm dec31ly; /* 12/31 last year */ + + dec31ly = *t; + dec31ly.tm_year--; + dec31ly.tm_mon = 11; + dec31ly.tm_mday = 31; + dec31ly.tm_wday = (jan1day == SUNDAY) ? 6 : jan1day - 1; + dec31ly.tm_yday = 364 + ISLEAP(dec31ly.tm_year + 1900); + wnum = ISO8601weeknum(&dec31ly); } + break; + } - if (t->tm_mon == 11) - { - int wday, mday; + if (t->tm_mon == 11) { + int wday, mday; - wday = t->tm_wday; - mday = t->tm_mday; - if ((wday == MONDAY && (mday >= 29 && mday <= 31)) - || (wday == TUESDAY && (mday == 30 || mday == 31)) - || (wday == WEDNESDAY && mday == 31)) - wnum = 1; - } + wday = t->tm_wday; + mday = t->tm_mday; + if ((wday == MONDAY && (mday >= 29 && mday <= 31)) + || (wday == TUESDAY && (mday == 30 || mday == 31)) + || (wday == WEDNESDAY && mday == 31)) + wnum = 1; + } return wnum; } /* Draw the weekly view inside calendar panel. */ static void -draw_weekly_view (struct window *cwin, struct date *current_day, - unsigned sunday_first) +draw_weekly_view(struct window *cwin, struct date *current_day, + unsigned sunday_first) { #define DAYSLICESNO 6 const int WCALWIDTH = 30; @@ -486,129 +443,123 @@ draw_weekly_view (struct window *cwin, struct date *current_day, struct tm t; int OFFX, j, c_wday, days_to_remove, weeknum; - OFFX = (wins_sbar_width () - WCALWIDTH) / 2 + 1; + OFFX = (wins_sbar_width() - WCALWIDTH) / 2 + 1; /* Fill in a tm structure with the first day of the selected week. */ - c_wday = calendar_get_wday (&slctd_day); + c_wday = calendar_get_wday(&slctd_day); if (sunday_first) days_to_remove = c_wday; else days_to_remove = c_wday == 0 ? WEEKINDAYS - 1 : c_wday - 1; - (void)memset (&t, 0, sizeof (struct tm)); + memset(&t, 0, sizeof(struct tm)); t.tm_mday = slctd_day.dd; t.tm_mon = slctd_day.mm - 1; t.tm_year = slctd_day.yyyy - 1900; - (void)mktime (&t); - (void)date_change (&t, 0, -days_to_remove); + mktime(&t); + date_change(&t, 0, -days_to_remove); /* Print the week number. */ - weeknum = ISO8601weeknum (&t); - custom_apply_attr (cwin->p, ATTR_HIGHEST); - mvwprintw (cwin->p, 2, cwin->w - 9, "(# %02d)", weeknum); - custom_remove_attr (cwin->p, ATTR_HIGHEST); + weeknum = ISO8601weeknum(&t); + custom_apply_attr(cwin->p, ATTR_HIGHEST); + mvwprintw(cwin->p, 2, cwin->w - 9, "(# %02d)", weeknum); + custom_remove_attr(cwin->p, ATTR_HIGHEST); /* Now draw calendar view. */ - for (j = 0; j < WEEKINDAYS; j++) - { - struct date date; - unsigned attr, item_this_day; - int i, slices[DAYSLICESNO]; - - /* print the day names, with regards to the first day of the week */ - custom_apply_attr (cwin->p, ATTR_HIGHEST); - mvwprintw (cwin->p, OFFY, OFFX + 4 * j, "%s", - _(daynames[1 + j - sunday_first])); - custom_remove_attr (cwin->p, ATTR_HIGHEST); - - /* Check if the day to be printed has an item or not. */ - date.dd = t.tm_mday; - date.mm = t.tm_mon + 1; - date.yyyy = t.tm_year + 1900; - item_this_day = day_check_if_item (date); - - /* Print the day numbers with appropriate decoration. */ - if (t.tm_mday == current_day->dd - && current_day->mm == slctd_day.mm - && current_day->yyyy == slctd_day.yyyy - && current_day->dd != slctd_day.dd) - attr = ATTR_LOWEST; /* today, but not selected */ - else if (t.tm_mday == slctd_day.dd) - attr = ATTR_HIGHEST; /* selected day */ - else if (item_this_day) - attr = ATTR_LOW; - else - attr = 0; - - if (attr) - custom_apply_attr (cwin->p, attr); - mvwprintw (cwin->p, OFFY + 1, OFFX + 1 + 4 * j, "%02d", t.tm_mday); - if (attr) - custom_remove_attr (cwin->p, attr); - - /* Draw slices indicating appointment times. */ - bzero (slices, DAYSLICESNO * sizeof *slices); - if (day_chk_busy_slices (date, DAYSLICESNO, slices)) - { - for (i = 0; i < DAYSLICESNO; i++) - { - if (j != WEEKINDAYS - 1 && i != DAYSLICESNO - 1) - mvwhline (cwin->p, OFFY + 2 + i, OFFX + 3 + 4 * j, ACS_S9, 2); - if (slices[i]) - { - int highlight; - - highlight = (t.tm_mday == slctd_day.dd) ? 1 : 0; - if (highlight) - custom_apply_attr (cwin->p, attr); - wattron (cwin->p, A_REVERSE); - mvwprintw (cwin->p, OFFY + 2 + i, OFFX + 1 + 4 * j, " "); - mvwprintw (cwin->p, OFFY + 2 + i, OFFX + 2 + 4 * j, " "); - wattroff (cwin->p, A_REVERSE); - if (highlight) - custom_remove_attr (cwin->p, attr); - } - } + for (j = 0; j < WEEKINDAYS; j++) { + struct date date; + unsigned attr, item_this_day; + int i, slices[DAYSLICESNO]; + + /* print the day names, with regards to the first day of the week */ + custom_apply_attr(cwin->p, ATTR_HIGHEST); + mvwprintw(cwin->p, OFFY, OFFX + 4 * j, "%s", + _(daynames[1 + j - sunday_first])); + custom_remove_attr(cwin->p, ATTR_HIGHEST); + + /* Check if the day to be printed has an item or not. */ + date.dd = t.tm_mday; + date.mm = t.tm_mon + 1; + date.yyyy = t.tm_year + 1900; + item_this_day = day_check_if_item(date); + + /* Print the day numbers with appropriate decoration. */ + if (t.tm_mday == current_day->dd + && current_day->mm == slctd_day.mm + && current_day->yyyy == slctd_day.yyyy + && current_day->dd != slctd_day.dd) + attr = ATTR_LOWEST; /* today, but not selected */ + else if (t.tm_mday == slctd_day.dd) + attr = ATTR_HIGHEST; /* selected day */ + else if (item_this_day) + attr = ATTR_LOW; + else + attr = 0; + + if (attr) + custom_apply_attr(cwin->p, attr); + mvwprintw(cwin->p, OFFY + 1, OFFX + 1 + 4 * j, "%02d", t.tm_mday); + if (attr) + custom_remove_attr(cwin->p, attr); + + /* Draw slices indicating appointment times. */ + memset(slices, 0, DAYSLICESNO * sizeof *slices); + if (day_chk_busy_slices(date, DAYSLICESNO, slices)) { + for (i = 0; i < DAYSLICESNO; i++) { + if (j != WEEKINDAYS - 1 && i != DAYSLICESNO - 1) + mvwhline(cwin->p, OFFY + 2 + i, OFFX + 3 + 4 * j, ACS_S9, 2); + if (slices[i]) { + int highlight; + + highlight = (t.tm_mday == slctd_day.dd) ? 1 : 0; + if (highlight) + custom_apply_attr(cwin->p, attr); + wattron(cwin->p, A_REVERSE); + mvwprintw(cwin->p, OFFY + 2 + i, OFFX + 1 + 4 * j, " "); + mvwprintw(cwin->p, OFFY + 2 + i, OFFX + 2 + 4 * j, " "); + wattroff(cwin->p, A_REVERSE); + if (highlight) + custom_remove_attr(cwin->p, attr); } - - /* get next day */ - (void)date_change (&t, 0, 1); + } } + /* get next day */ + date_change(&t, 0, 1); + } + /* Draw marks to indicate midday on the sides of the calendar. */ - custom_apply_attr (cwin->p, ATTR_HIGHEST); - mvwhline (cwin->p, OFFY + 1 + DAYSLICESNO / 2, OFFX, ACS_S9, 1); - mvwhline (cwin->p, OFFY + 1 + DAYSLICESNO / 2, - OFFX + WCALWIDTH - 3, ACS_S9, 1); - custom_remove_attr (cwin->p, ATTR_HIGHEST); + custom_apply_attr(cwin->p, ATTR_HIGHEST); + mvwhline(cwin->p, OFFY + 1 + DAYSLICESNO / 2, OFFX, ACS_S9, 1); + mvwhline(cwin->p, OFFY + 1 + DAYSLICESNO / 2, + OFFX + WCALWIDTH - 3, ACS_S9, 1); + custom_remove_attr(cwin->p, ATTR_HIGHEST); #undef DAYSLICESNO } /* Function used to display the calendar panel. */ -void -calendar_update_panel (struct window *cwin) +void calendar_update_panel(struct window *cwin) { struct date current_day; unsigned sunday_first; - calendar_store_current_date (¤t_day); - erase_window_part (cwin->p, 1, 3, cwin->w - 2, cwin->h - 2); - mvwhline (cwin->p, 2, 1, ACS_HLINE, cwin->w - 2); - sunday_first = calendar_week_begins_on_monday () ? 0 : 1; + calendar_store_current_date(¤t_day); + erase_window_part(cwin->p, 1, 3, cwin->w - 2, cwin->h - 2); + mvwhline(cwin->p, 2, 1, ACS_HLINE, cwin->w - 2); + sunday_first = calendar_week_begins_on_monday()? 0 : 1; draw_calendar[calendar_view] (cwin, ¤t_day, sunday_first); - wnoutrefresh (cwin->p); + wnoutrefresh(cwin->p); } /* Set the selected day in calendar to current day. */ -void -calendar_goto_today (void) +void calendar_goto_today(void) { struct date today; - calendar_store_current_date (&today); + calendar_store_current_date(&today); slctd_day.dd = today.dd; slctd_day.mm = today.mm; slctd_day.yyyy = today.yyyy; @@ -620,154 +571,143 @@ calendar_goto_today (void) * If the entered date is empty, automatically jump to the current date. * slctd_day is updated with the newly selected date. */ -void -calendar_change_day (int datefmt) +void calendar_change_day(int datefmt) { #define LDAY 11 char selected_day[LDAY] = ""; char outstr[BUFSIZ]; int dday, dmonth, dyear; int wrong_day = 1; - char *mesg_line1 = - _("The day you entered is not valid " - "(should be between 01/01/1902 and 12/31/2037)"); - char *mesg_line2 = _("Press [ENTER] to continue"); - char *request_date = "Enter the day to go to [ENTER for today] : %s"; - - while (wrong_day) - { - (void)snprintf (outstr, BUFSIZ, request_date, DATEFMT_DESC (datefmt)); - status_mesg (_(outstr), ""); - if (getstring (win[STA].p, selected_day, LDAY, 0, 1) == GETSTRING_ESC) - return; - else - { - if (strlen (selected_day) == 0) - { - wrong_day = 0; - calendar_goto_today (); - } - else if (parse_date (selected_day, datefmt, &dyear, &dmonth, &dday, - calendar_get_slctd_day ())) - { - wrong_day = 0; - /* go to chosen day */ - slctd_day.dd = dday; - slctd_day.mm = dmonth; - slctd_day.yyyy = dyear; - } - if (wrong_day) - { - status_mesg (mesg_line1, mesg_line2); - (void)wgetch (win[STA].p); - } - } + const char *mesg_line1 = + _("The day you entered is not valid " + "(should be between 01/01/1902 and 12/31/2037)"); + const char *mesg_line2 = _("Press [ENTER] to continue"); + const char *request_date = "Enter the day to go to [ENTER for today] : %s"; + + while (wrong_day) { + snprintf(outstr, BUFSIZ, request_date, DATEFMT_DESC(datefmt)); + status_mesg(_(outstr), ""); + if (getstring(win[STA].p, selected_day, LDAY, 0, 1) == GETSTRING_ESC) + return; + else { + if (strlen(selected_day) == 0) { + wrong_day = 0; + calendar_goto_today(); + } else if (parse_date(selected_day, datefmt, &dyear, &dmonth, &dday, + calendar_get_slctd_day())) { + wrong_day = 0; + /* go to chosen day */ + slctd_day.dd = dday; + slctd_day.mm = dmonth; + slctd_day.yyyy = dyear; + } + if (wrong_day) { + status_mesg(mesg_line1, mesg_line2); + wgetch(win[STA].p); + } } + } return; } -void -calendar_move (enum move move) +void calendar_move(enum move move, int count) { int ret, days_to_remove, days_to_add; struct tm t; - (void)memset (&t, 0, sizeof (struct tm)); + memset(&t, 0, sizeof(struct tm)); t.tm_mday = slctd_day.dd; t.tm_mon = slctd_day.mm - 1; t.tm_year = slctd_day.yyyy - 1900; - switch (move) - { - case UP: - if ((slctd_day.dd <= 7) && (slctd_day.mm == 1) - && (slctd_day.yyyy == 1902)) - return; - ret = date_change (&t, 0, -WEEKINDAYS); - break; - case DOWN: - if ((slctd_day.dd > days[slctd_day.mm - 1] - 7) - && (slctd_day.mm == 12) && (slctd_day.yyyy == 2037)) - return; - ret = date_change (&t, 0, WEEKINDAYS); - break; - case LEFT: - if ((slctd_day.dd == 1) && (slctd_day.mm == 1) - && (slctd_day.yyyy == 1902)) - return; - ret = date_change (&t, 0, -1); - break; - case RIGHT: - if ((slctd_day.dd == 31) && (slctd_day.mm == 12) - && (slctd_day.yyyy == 2037)) - return; - ret = date_change (&t, 0, 1); - break; - case WEEK_START: - /* Normalize struct tm to get week day number. */ - (void)mktime (&t); - if (calendar_week_begins_on_monday ()) - days_to_remove = ((t.tm_wday == 0) ? WEEKINDAYS - 1 : t.tm_wday - 1); - else - days_to_remove = ((t.tm_wday == 0) ? 0 : t.tm_wday); - ret = date_change (&t, 0, 0 - days_to_remove); - break; - case WEEK_END: - (void)mktime (&t); - if (calendar_week_begins_on_monday ()) - days_to_add = ((t.tm_wday == 0) ? 0 : WEEKINDAYS - t.tm_wday); - else - days_to_add = ((t.tm_wday == 0) ? - WEEKINDAYS - 1 : WEEKINDAYS - 1 - t.tm_wday); - ret = date_change (&t, 0, days_to_add); - break; - default: - ret = 1; - /* NOTREACHED */ - } - if (ret == 0) - { - slctd_day.dd = t.tm_mday; - slctd_day.mm = t.tm_mon + 1; - slctd_day.yyyy = t.tm_year + 1900; + switch (move) { + case UP: + ret = date_change(&t, 0, -count * WEEKINDAYS); + break; + case DOWN: + ret = date_change(&t, 0, count * WEEKINDAYS); + break; + case LEFT: + ret = date_change(&t, 0, -count); + break; + case RIGHT: + ret = date_change(&t, 0, count); + break; + case WEEK_START: + /* Normalize struct tm to get week day number. */ + mktime(&t); + if (calendar_week_begins_on_monday()) + days_to_remove = ((t.tm_wday == 0) ? WEEKINDAYS - 1 : t.tm_wday - 1); + else + days_to_remove = ((t.tm_wday == 0) ? 0 : t.tm_wday); + days_to_remove += (count - 1) * WEEKINDAYS; + ret = date_change(&t, 0, -days_to_remove); + break; + case WEEK_END: + mktime(&t); + if (calendar_week_begins_on_monday()) + days_to_add = ((t.tm_wday == 0) ? 0 : WEEKINDAYS - t.tm_wday); + else + days_to_add = ((t.tm_wday == 0) ? + WEEKINDAYS - 1 : WEEKINDAYS - 1 - t.tm_wday); + days_to_add += (count - 1) * WEEKINDAYS; + ret = date_change(&t, 0, days_to_add); + break; + default: + ret = 1; + /* NOTREACHED */ + } + + if (ret == 0) { + if (t.tm_year < 2) { + t.tm_mday = 1; + t.tm_mon = 0; + t.tm_year = 2; + } else if (t.tm_year > 137) { + t.tm_mday = 31; + t.tm_mon = 11; + t.tm_year = 137; } + + slctd_day.dd = t.tm_mday; + slctd_day.mm = t.tm_mon + 1; + slctd_day.yyyy = t.tm_year + 1900; + } } /* Returns the beginning of current year as a long. */ -long -calendar_start_of_year (void) +long calendar_start_of_year(void) { time_t timer; struct tm *tm; - timer = time (NULL); - tm = localtime (&timer); + timer = time(NULL); + tm = localtime(&timer); tm->tm_mon = 0; tm->tm_mday = 1; tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; - timer = mktime (tm); + timer = mktime(tm); return (long)timer; } -long -calendar_end_of_year (void) +long calendar_end_of_year(void) { time_t timer; struct tm *tm; - timer = time (NULL); - tm = localtime (&timer); + timer = time(NULL); + tm = localtime(&timer); tm->tm_mon = 0; tm->tm_mday = 1; tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; tm->tm_year++; - timer = mktime (tm); + timer = mktime(tm); return (long)(timer - 1); } @@ -813,18 +753,16 @@ calendar_end_of_year (void) * dtor -- * convert degrees to radians */ -static double -dtor (double deg) +static double dtor(double deg) { - return (deg * M_PI / 180); + return deg * M_PI / 180; } /* * adj360 -- * adjust value so 0 <= deg <= 360 */ -static void -adj360 (double *deg) +static void adj360(double *deg) { for (;;) if (*deg < 0.0) @@ -839,36 +777,35 @@ adj360 (double *deg) * potm -- * return phase of the moon */ -static double -potm (double days) +static double potm(double days) { double N, Msol, Ec, LambdaSol, l, Mm, Ev, Ac, A3, Mmprime; double A4, lprime, V, ldprime, D, Nm; - N = 360.0 * days / 365.242191; /* sec 46 #3 */ - adj360 (&N); - Msol = N + EPSILONg - RHOg; /* sec 46 #4 */ - adj360 (&Msol); - Ec = 360 / M_PI * ECCEN * sin (dtor (Msol)); /* sec 46 #5 */ - LambdaSol = N + Ec + EPSILONg; /* sec 46 #6 */ - adj360 (&LambdaSol); - l = 13.1763966 * days + lzero; /* sec 65 #4 */ - adj360 (&l); - Mm = l - (0.1114041 * days) - Pzero; /* sec 65 #5 */ - adj360 (&Mm); - Nm = Nzero - (0.0529539 * days); /* sec 65 #6 */ - adj360 (&Nm); - Ev = 1.2739 * sin (dtor (2 * (l - LambdaSol) - Mm)); /* sec 65 #7 */ - Ac = 0.1858 * sin (dtor (Msol)); /* sec 65 #8 */ - A3 = 0.37 * sin (dtor (Msol)); - Mmprime = Mm + Ev - Ac - A3; /* sec 65 #9 */ - Ec = 6.2886 * sin (dtor (Mmprime)); /* sec 65 #10 */ - A4 = 0.214 * sin (dtor (2 * Mmprime)); /* sec 65 #11 */ - lprime = l + Ev + Ec - Ac + A4; /* sec 65 #12 */ - V = 0.6583 * sin (dtor (2 * (lprime - LambdaSol))); /* sec 65 #13 */ - ldprime = lprime + V; /* sec 65 #14 */ - D = ldprime - LambdaSol; /* sec 67 #2 */ - return (50.0 * (1 - cos (dtor (D)))); /* sec 67 #3 */ + N = 360.0 * days / 365.242191; /* sec 46 #3 */ + adj360(&N); + Msol = N + EPSILONg - RHOg; /* sec 46 #4 */ + adj360(&Msol); + Ec = 360 / M_PI * ECCEN * sin(dtor(Msol)); /* sec 46 #5 */ + LambdaSol = N + Ec + EPSILONg; /* sec 46 #6 */ + adj360(&LambdaSol); + l = 13.1763966 * days + lzero; /* sec 65 #4 */ + adj360(&l); + Mm = l - (0.1114041 * days) - Pzero; /* sec 65 #5 */ + adj360(&Mm); + Nm = Nzero - (0.0529539 * days); /* sec 65 #6 */ + adj360(&Nm); + Ev = 1.2739 * sin(dtor(2 * (l - LambdaSol) - Mm)); /* sec 65 #7 */ + Ac = 0.1858 * sin(dtor(Msol)); /* sec 65 #8 */ + A3 = 0.37 * sin(dtor(Msol)); + Mmprime = Mm + Ev - Ac - A3; /* sec 65 #9 */ + Ec = 6.2886 * sin(dtor(Mmprime)); /* sec 65 #10 */ + A4 = 0.214 * sin(dtor(2 * Mmprime)); /* sec 65 #11 */ + lprime = l + Ev + Ec - Ac + A4; /* sec 65 #12 */ + V = 0.6583 * sin(dtor(2 * (lprime - LambdaSol))); /* sec 65 #13 */ + ldprime = lprime + V; /* sec 65 #14 */ + D = ldprime - LambdaSol; /* sec 67 #2 */ + return 50.0 * (1 - cos(dtor(D))); /* sec 67 #3 */ } /* @@ -882,23 +819,22 @@ potm (double days) * Updated to the Third Edition of Duffett-Smith's book, IX 1998 * */ -static double -pom (time_t tmpt) +static double pom(time_t tmpt) { struct tm *GMT; double days; int cnt; - GMT = gmtime (&tmpt); + GMT = gmtime(&tmpt); days = (GMT->tm_yday + 1) + ((GMT->tm_hour + (GMT->tm_min / 60.0) + (GMT->tm_sec / 3600.0)) / 24.0); for (cnt = EPOCH; cnt < GMT->tm_year; ++cnt) - days += ISLEAP (cnt + TM_YEAR_BASE) ? 366 : 365; + days += ISLEAP(cnt + TM_YEAR_BASE) ? 366 : 365; /* Selected time could be before EPOCH */ for (cnt = GMT->tm_year; cnt < EPOCH; ++cnt) - days -= ISLEAP (cnt + TM_YEAR_BASE) ? 366 : 365; + days -= ISLEAP(cnt + TM_YEAR_BASE) ? 366 : 365; - return (potm (days)); + return potm(days); } /* @@ -906,25 +842,24 @@ pom (time_t tmpt) * Careful: date is the selected day in calendar at 00:00, so it represents * the phase of the moon for previous day. */ -char * -calendar_get_pom (time_t date) +const char *calendar_get_pom(time_t date) { - char *pom_pict[MOON_PHASES] = { " ", "|) ", "(|)", "(| ", " | " }; + const char *pom_pict[MOON_PHASES] = { " ", "|) ", "(|)", "(| ", " | " }; enum pom phase = NO_POM; double pom_today, relative_pom, pom_yesterday, pom_tomorrow; const double half = 50.0; - pom_yesterday = pom (date); - pom_today = pom (date + DAYINSEC); - relative_pom = abs (pom_today - half); - pom_tomorrow = pom (date + 2 * DAYINSEC); + pom_yesterday = pom(date); + pom_today = pom(date + DAYINSEC); + relative_pom = abs(pom_today - half); + pom_tomorrow = pom(date + 2 * DAYINSEC); if (pom_today > pom_yesterday && pom_today > pom_tomorrow) phase = FULL_MOON; else if (pom_today < pom_yesterday && pom_today < pom_tomorrow) phase = NEW_MOON; - else if (relative_pom < abs (pom_yesterday - half) - && relative_pom < abs (pom_tomorrow - half)) + else if (relative_pom < abs(pom_yesterday - half) + && relative_pom < abs(pom_tomorrow - half)) phase = (pom_tomorrow > pom_today) ? FIRST_QUARTER : LAST_QUARTER; - return (pom_pict[phase]); + return pom_pict[phase]; } diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..edf1f3b --- /dev/null +++ b/src/config.c @@ -0,0 +1,574 @@ +/* + * 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 <ctype.h> +#include <unistd.h> + +#include "calcurse.h" + +typedef int (*config_fn_parse_t) (void *, const char *); +typedef int (*config_fn_serialize_t) (char *, void *); + +struct confvar { + const char *key; + config_fn_parse_t fn_parse; + config_fn_serialize_t fn_serialize; + void *target; +}; + +static int config_parse_bool(unsigned *, const char *); +static int config_serialize_bool(char *, unsigned *); +static int config_parse_int(int *, const char *); +static int config_serialize_int(char *, int *); +static int config_parse_unsigned(unsigned *, const char *); +static int config_serialize_unsigned(char *, unsigned *); +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_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 *); +static int config_serialize_color_theme(char *, void *); +static int config_parse_layout(void *, const char *); +static int config_serialize_layout(char *, void *); +static int config_parse_sidebar_width(void *, const char *); +static int config_serialize_sidebar_width(char *, void *); +static int config_parse_output_datefmt(void *, const char *); +static int config_serialize_output_datefmt(char *, void *); +static int config_parse_input_datefmt(void *, const char *); +static int config_serialize_input_datefmt(char *, void *); + +#define CONFIG_HANDLER_BOOL(var) (config_fn_parse_t) config_parse_bool, \ + (config_fn_serialize_t) config_serialize_bool, &(var) +#define CONFIG_HANDLER_INT(var) (config_fn_parse_t) config_parse_int, \ + (config_fn_serialize_t) config_serialize_int, &(var) +#define CONFIG_HANDLER_UNSIGNED(var) (config_fn_parse_t) config_parse_unsigned, \ + (config_fn_serialize_t) config_serialize_unsigned, &(var) +#define CONFIG_HANDLER_STR(var) (config_fn_parse_t) config_parse_str, \ + (config_fn_serialize_t) config_serialize_str, &(var) + +static const struct confvar confmap[] = { + {"appearance.calendarview", config_parse_calendar_view, + config_serialize_calendar_view, NULL}, + {"appearance.layout", config_parse_layout, config_serialize_layout, NULL}, + {"appearance.notifybar", CONFIG_HANDLER_BOOL(nbar.show)}, + {"appearance.sidebarwidth", config_parse_sidebar_width, + config_serialize_sidebar_width, NULL}, + {"appearance.theme", config_parse_color_theme, config_serialize_color_theme, + NULL}, + {"daemon.enable", CONFIG_HANDLER_BOOL(dmon.enable)}, + {"daemon.log", CONFIG_HANDLER_BOOL(dmon.log)}, + {"format.inputdate", config_parse_input_datefmt, + config_serialize_input_datefmt, NULL}, + {"format.notifydate", CONFIG_HANDLER_STR(nbar.datefmt)}, + {"format.notifytime", CONFIG_HANDLER_STR(nbar.timefmt)}, + {"format.outputdate", config_parse_output_datefmt, + config_serialize_output_datefmt, NULL}, + {"general.autogc", CONFIG_HANDLER_BOOL(conf.auto_gc)}, + {"general.autosave", CONFIG_HANDLER_BOOL(conf.auto_save)}, + {"general.confirmdelete", CONFIG_HANDLER_BOOL(conf.confirm_delete)}, + {"general.confirmquit", CONFIG_HANDLER_BOOL(conf.confirm_quit)}, + {"general.firstdayofweek", config_parse_first_day_of_week, + config_serialize_first_day_of_week, NULL}, + {"general.periodicsave", CONFIG_HANDLER_UNSIGNED(conf.periodic_save)}, + {"general.progressbar", CONFIG_HANDLER_BOOL(conf.progress_bar)}, + {"general.systemdialogs", CONFIG_HANDLER_BOOL(conf.system_dialogs)}, + {"notification.command", CONFIG_HANDLER_STR(nbar.cmd)}, + {"notification.notifyall", CONFIG_HANDLER_BOOL(nbar.notify_all)}, + {"notification.warning", CONFIG_HANDLER_INT(nbar.cntdwn)} +}; + +struct config_save_status { + FILE *fp; + int done[sizeof(confmap) / sizeof(confmap[0])]; +}; + +typedef int (*config_fn_walk_cb_t) (const char *, const char *, void *); +typedef int (*config_fn_walk_junk_cb_t) (const char *, void *); + +static int config_parse_bool(unsigned *dest, const char *val) +{ + if (strcmp(val, "yes") == 0) + *dest = 1; + else if (strcmp(val, "no") == 0) + *dest = 0; + else + return 0; + + return 1; +} + +static int config_parse_unsigned(unsigned *dest, const char *val) +{ + if (is_all_digit(val)) + *dest = atoi(val); + else + return 0; + + return 1; +} + +static int config_parse_int(int *dest, const char *val) +{ + if ((*val == '+' || *val == '-' || isdigit(*val)) && is_all_digit(val + 1)) + *dest = atoi(val); + else + return 0; + + return 1; +} + +static int config_parse_str(char *dest, const char *val) +{ + strncpy(dest, val, BUFSIZ); + return 1; +} + +static int config_parse_color(int *dest, const char *val) +{ + if (!strcmp(val, "black")) + *dest = COLOR_BLACK; + else if (!strcmp(val, "red")) + *dest = COLOR_RED; + else if (!strcmp(val, "green")) + *dest = COLOR_GREEN; + else if (!strcmp(val, "yellow")) + *dest = COLOR_YELLOW; + else if (!strcmp(val, "blue")) + *dest = COLOR_BLUE; + else if (!strcmp(val, "magenta")) + *dest = COLOR_MAGENTA; + else if (!strcmp(val, "cyan")) + *dest = COLOR_CYAN; + else if (!strcmp(val, "white")) + *dest = COLOR_WHITE; + else if (!strcmp(val, "default")) + *dest = background; + else + return 0; + + return 1; +} + +static int config_parse_color_pair(int *dest1, int *dest2, const char *val) +{ + char s1[BUFSIZ], s2[BUFSIZ]; + + if (sscanf(val, "%s on %s", s1, s2) != 2) + return 0; + + return (config_parse_color(dest1, s1) && config_parse_color(dest2, s2)); +} + +static int config_parse_calendar_view(void *dummy, const char *val) +{ + calendar_set_view(atoi(val)); + return 1; +} + +static int config_parse_first_day_of_week(void *dummy, const char *val) +{ + if (!strcmp(val, "monday")) + calendar_set_first_day_of_week(MONDAY); + else if (!strcmp(val, "sunday")) + calendar_set_first_day_of_week(SUNDAY); + else + return 0; + + return 1; +} + +static int config_parse_color_theme(void *dummy, const char *val) +{ + int color1, color2; + if (!config_parse_color_pair(&color1, &color2, val)) + return 0; + init_pair(COLR_CUSTOM, color1, color2); + return 1; +} + +static int config_parse_layout(void *dummy, const char *val) +{ + wins_set_layout(atoi(val)); + return 1; +} + +static int config_parse_sidebar_width(void *dummy, const char *val) +{ + wins_set_sbar_width(atoi(val)); + return 1; +} + +static int config_parse_output_datefmt(void *dummy, const char *val) +{ + if (val[0] != '\0') + return config_parse_str(conf.output_datefmt, val); + return 1; +} + +static int config_parse_input_datefmt(void *dummy, const char *val) +{ + if (config_parse_int(&conf.input_datefmt, val)) { + if (conf.input_datefmt <= 0 || conf.input_datefmt >= DATE_FORMATS) + conf.input_datefmt = 1; + return 1; + } else + return 0; +} + +/* Set a configuration variable. */ +static int config_set_conf(const char *key, const char *value) +{ + int i; + + if (!key) + return -1; + + for (i = 0; i < sizeof(confmap) / sizeof(confmap[0]); i++) { + if (!strcmp(confmap[i].key, key)) + return confmap[i].fn_parse(confmap[i].target, value); + } + + return -1; +} + +static int config_serialize_bool(char *dest, unsigned *val) +{ + if (*val) { + dest[0] = 'y'; + dest[1] = 'e'; + dest[2] = 's'; + dest[3] = '\0'; + } else { + dest[0] = 'n'; + dest[1] = 'o'; + dest[2] = '\0'; + } + + return 1; +} + +static int config_serialize_unsigned(char *dest, unsigned *val) +{ + snprintf(dest, BUFSIZ, "%u", *val); + return 1; +} + +static int config_serialize_int(char *dest, int *val) +{ + snprintf(dest, BUFSIZ, "%d", *val); + return 1; +} + +static int config_serialize_str(char *dest, const char *val) +{ + strncpy(dest, val, BUFSIZ); + return 1; +} + +/* + * Return a string defining the color theme in the form: + * foreground color 'on' background color + * in order to dump this data in the configuration file. + * Color numbers follow the ncurses library definitions. + * If ncurses library was compiled with --enable-ext-funcs, + * then default color is -1. + */ +static void config_color_theme_name(char *theme_name) +{ +#define MAXCOLORS 8 +#define NBCOLORS 2 +#define DEFAULTCOLOR 255 +#define DEFAULTCOLOR_EXT -1 + + int i; + short color[NBCOLORS]; + const char *color_name[NBCOLORS]; + const char *default_color = "default"; + const char *name[MAXCOLORS] = { + "black", + "red", + "green", + "yellow", + "blue", + "magenta", + "cyan", + "white" + }; + + if (!colorize) + strncpy(theme_name, "0", BUFSIZ); + else { + pair_content(COLR_CUSTOM, &color[0], &color[1]); + for (i = 0; i < NBCOLORS; i++) { + if ((color[i] == DEFAULTCOLOR) || (color[i] == DEFAULTCOLOR_EXT)) + color_name[i] = default_color; + else if (color[i] >= 0 && color[i] <= MAXCOLORS) + color_name[i] = name[color[i]]; + else { + EXIT(_("unknown color")); + /* NOTREACHED */ + } + } + snprintf(theme_name, BUFSIZ, "%s on %s", color_name[0], color_name[1]); + } +} + +static int config_serialize_calendar_view(char *buf, void *dummy) +{ + int tmp = calendar_get_view(); + return config_serialize_int(buf, &tmp); +} + +static int config_serialize_first_day_of_week(char *buf, void *dummy) +{ + if (calendar_week_begins_on_monday()) + strcpy(buf, "monday"); + else + strcpy(buf, "sunday"); + + return 1; +} + +static int config_serialize_color_theme(char *buf, void *dummy) +{ + config_color_theme_name(buf); + return 1; +} + +static int config_serialize_layout(char *buf, void *dummy) +{ + int tmp = wins_layout(); + return config_serialize_int(buf, &tmp); +} + +static int config_serialize_sidebar_width(char *buf, void *dummy) +{ + int tmp = wins_sbar_wperc(); + return config_serialize_int(buf, &tmp); +} + +static int config_serialize_output_datefmt(char *buf, void *dummy) +{ + return config_serialize_str(buf, conf.output_datefmt); +} + +static int config_serialize_input_datefmt(char *buf, void *dummy) +{ + return config_serialize_int(buf, &conf.input_datefmt); +} + +/* Serialize the value of a configuration variable. */ +static int +config_serialize_conf(char *buf, const char *key, + struct config_save_status *status) +{ + int i; + + if (!key) + return -1; + + for (i = 0; i < sizeof(confmap) / sizeof(confmap[0]); i++) { + if (!strcmp(confmap[i].key, key)) { + if (confmap[i].fn_serialize(buf, confmap[i].target)) { + if (status) + status->done[i] = 1; + return 1; + } else + return 0; + } + } + + return -1; +} + +static void +config_file_walk(config_fn_walk_cb_t fn_cb, + config_fn_walk_junk_cb_t fn_junk_cb, void *data) +{ + FILE *data_file; + char buf[BUFSIZ], e_conf[BUFSIZ]; + char *key, *value; + + data_file = fopen(path_conf, "r"); + EXIT_IF(data_file == NULL, _("failed to open configuration file")); + + pthread_mutex_lock(&nbar.mutex); + for (;;) { + if (fgets(buf, sizeof buf, data_file) == NULL) + break; + io_extract_data(e_conf, buf, sizeof buf); + + if (*e_conf == '\0') { + if (fn_junk_cb) + fn_junk_cb(buf, data); + continue; + } + + key = e_conf; + value = strchr(e_conf, '='); + if (value) { + *value = '\0'; + value++; + } + + if (strcmp(key, "auto_save") == 0 || + strcmp(key, "auto_gc") == 0 || + strcmp(key, "periodic_save") == 0 || + strcmp(key, "confirm_quit") == 0 || + strcmp(key, "confirm_delete") == 0 || + strcmp(key, "skip_system_dialogs") == 0 || + strcmp(key, "skip_progress_bar") == 0 || + strcmp(key, "calendar_default_view") == 0 || + strcmp(key, "week_begins_on_monday") == 0 || + strcmp(key, "color-theme") == 0 || + strcmp(key, "layout") == 0 || + strcmp(key, "side-bar_width") == 0 || + strcmp(key, "notify-bar_show") == 0 || + strcmp(key, "notify-bar_date") == 0 || + strcmp(key, "notify-bar_clock") == 0 || + strcmp(key, "notify-bar_warning") == 0 || + strcmp(key, "notify-bar_command") == 0 || + strcmp(key, "notify-all") == 0 || + strcmp(key, "output_datefmt") == 0 || + strcmp(key, "input_datefmt") == 0 || + strcmp(key, "notify-daemon_enable") == 0 || + strcmp(key, "notify-daemon_log") == 0) { + WARN_MSG(_("Pre-3.0.0 configuration file format detected, " + "please upgrade running `calcurse-upgrade`.")); + } + + if (value && (*value == '\0' || *value == '\n')) { + /* Backward compatibility mode. */ + if (fgets(buf, sizeof buf, data_file) == NULL) + break; + io_extract_data(e_conf, buf, sizeof buf); + value = e_conf; + } + + fn_cb(key, value, data); + } + file_close(data_file, __FILE_POS__); + pthread_mutex_unlock(&nbar.mutex); +} + +static int config_load_cb(const char *key, const char *value, void *dummy) +{ + int result = config_set_conf(key, value); + + if (result < 0) + EXIT(_("configuration variable unknown: \"%s\""), key); + /* NOTREACHED */ + else if (result == 0) + EXIT(_("wrong configuration variable format for \"%s\""), key); + /* NOTREACHED */ + + return 1; +} + +/* Load the user configuration. */ +void config_load(void) +{ + config_file_walk(config_load_cb, NULL, NULL); +} + +static int config_save_cb(const char *key, const char *value, void *status) +{ + char buf[BUFSIZ]; + int result = + config_serialize_conf(buf, key, (struct config_save_status *)status); + + if (result < 0) + EXIT(_("configuration variable unknown: \"%s\""), key); + /* NOTREACHED */ + else if (result == 0) + EXIT(_("wrong configuration variable format for \"%s\""), key); + /* NOTREACHED */ + + fputs(key, ((struct config_save_status *)status)->fp); + fputc('=', ((struct config_save_status *)status)->fp); + fputs(buf, ((struct config_save_status *)status)->fp); + fputc('\n', ((struct config_save_status *)status)->fp); + + return 1; +} + +static int config_save_junk_cb(const char *data, void *status) +{ + fputs(data, ((struct config_save_status *)status)->fp); + return 1; +} + +/* Save the user configuration. */ +unsigned config_save(void) +{ + char tmppath[BUFSIZ]; + char *tmpext; + struct config_save_status status; + int i; + + if (read_only) + return 1; + + strncpy(tmppath, get_tempdir(), BUFSIZ); + strncat(tmppath, "/" CONF_PATH_NAME ".", BUFSIZ - strlen(tmppath) - 1); + if ((tmpext = new_tempfile(tmppath, TMPEXTSIZ)) == NULL) + return 0; + strncat(tmppath, tmpext, BUFSIZ - strlen(tmppath) - 1); + mem_free(tmpext); + + status.fp = fopen(tmppath, "w"); + if (!status.fp) + return 0; + + memset(status.done, 0, sizeof(status.done)); + + config_file_walk(config_save_cb, config_save_junk_cb, (void *)&status); + + /* Set variables that were missing from the configuration file. */ + for (i = 0; i < sizeof(confmap) / sizeof(confmap[0]); i++) { + if (!status.done[i]) + config_save_cb(confmap[i].key, NULL, &status); + } + + file_close(status.fp, __FILE_POS__); + + if (io_file_cp(tmppath, path_conf)) + unlink(tmppath); + + return 1; +} diff --git a/src/custom.c b/src/custom.c index 1f75978..ef84703 100644 --- a/src/custom.c +++ b/src/custom.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -37,35 +37,10 @@ #include <string.h> #include <stdlib.h> #include <math.h> +#include <ctype.h> #include "calcurse.h" -/* Available configuration variables. */ -enum conf_var { - CUSTOM_CONF_NOVARIABLE, - CUSTOM_CONF_AUTOSAVE, - CUSTOM_CONF_PERIODICSAVE, - CUSTOM_CONF_CONFIRMQUIT, - CUSTOM_CONF_CONFIRMDELETE, - CUSTOM_CONF_SKIPSYSTEMDIALOGS, - CUSTOM_CONF_SKIPPROGRESSBAR, - CUSTOM_CONF_CALENDAR_DEFAULTVIEW, - CUSTOM_CONF_WEEKBEGINSONMONDAY, - CUSTOM_CONF_COLORTHEME, - CUSTOM_CONF_LAYOUT, - CUSTOM_CONF_SBAR_WIDTH, - CUSTOM_CONF_NOTIFYBARSHOW, - CUSTOM_CONF_NOTIFYBARDATE, - CUSTOM_CONF_NOTIFYBARCLOCK, - CUSTOM_CONF_NOTIFYBARWARNING, - CUSTOM_CONF_NOTIFYBARCOMMAND, - CUSTOM_CONF_OUTPUTDATEFMT, - CUSTOM_CONF_INPUTDATEFMT, - CUSTOM_CONF_DMON_ENABLE, - CUSTOM_CONF_DMON_LOG, - CUSTOM_CONF_VARIABLES -}; - struct attribute { int color[7]; int nocolor[7]; @@ -73,118 +48,6 @@ struct attribute { static struct attribute attr; -static unsigned -fill_config_var (char *string) -{ - if (strncmp (string, "yes", 3) == 0) - return 1; - else if (strncmp (string, "no", 2) == 0) - return 0; - else - { - EXIT (_("wrong configuration variable format.")); - return 0; - } -} - -/* - * Load user color theme from file. - * Need to handle calcurse versions prior to 1.8, where colors where handled - * differently (number between 1 and 8). - */ -static void -custom_load_color (char *color, int background) -{ -#define AWAITED_COLORS 2 - - int i, len, color_num; - char c[AWAITED_COLORS][BUFSIZ]; - int colr[AWAITED_COLORS]; - - len = strlen (color); - if (len > 1) - { - /* New version configuration */ - if (sscanf (color, "%s on %s", c[0], c[1]) != AWAITED_COLORS) - { - EXIT (_("missing colors in config file")); - /* NOTREACHED */ - } - - for (i = 0; i < AWAITED_COLORS; i++) - { - if (!strncmp (c[i], "black", 5)) - colr[i] = COLOR_BLACK; - else if (!strncmp (c[i], "red", 3)) - colr[i] = COLOR_RED; - else if (!strncmp (c[i], "green", 5)) - colr[i] = COLOR_GREEN; - else if (!strncmp (c[i], "yellow", 6)) - colr[i] = COLOR_YELLOW; - else if (!strncmp (c[i], "blue", 4)) - colr[i] = COLOR_BLUE; - else if (!strncmp (c[i], "magenta", 7)) - colr[i] = COLOR_MAGENTA; - else if (!strncmp (c[i], "cyan", 4)) - colr[i] = COLOR_CYAN; - else if (!strncmp (c[i], "white", 5)) - colr[i] = COLOR_WHITE; - else if (!strncmp (c[i], "default", 7)) - colr[i] = background; - else - { - EXIT (_("wrong color name")); - /* NOTREACHED */ - } - } - init_pair (COLR_CUSTOM, colr[0], colr[1]); - } - else if (len > 0 && len < 2) - { - /* Old version configuration */ - color_num = atoi (color); - - switch (color_num) - { - case 0: - colorize = 0; - break; - case 1: - init_pair (COLR_CUSTOM, COLOR_RED, background); - break; - case 2: - init_pair (COLR_CUSTOM, COLOR_GREEN, background); - break; - case 3: - init_pair (COLR_CUSTOM, COLOR_BLUE, background); - break; - case 4: - init_pair (COLR_CUSTOM, COLOR_CYAN, background); - break; - case 5: - init_pair (COLR_CUSTOM, COLOR_YELLOW, background); - break; - case 6: - init_pair (COLR_CUSTOM, COLOR_BLACK, COLR_GREEN); - break; - case 7: - init_pair (COLR_CUSTOM, COLOR_BLACK, COLR_YELLOW); - break; - case 8: - init_pair (COLR_CUSTOM, COLOR_RED, COLR_BLUE); - break; - default: - EXIT (_("wrong color number")); - /* NOTREACHED */ - } - } - else - { - EXIT (_("wrong configuration variable format")); - /* NOTREACHED */ - } -} - /* * Define window attributes (for both color and non-color terminals): * ATTR_HIGHEST are for window titles @@ -193,16 +56,15 @@ custom_load_color (char *color, int background) * ATTR_LOW are for days inside calendar panel which contains an event * ATTR_LOWEST are for current day inside calendar panel */ -void -custom_init_attr (void) +void custom_init_attr(void) { - attr.color[ATTR_HIGHEST] = COLOR_PAIR (COLR_CUSTOM); - attr.color[ATTR_HIGH] = COLOR_PAIR (COLR_HIGH); - attr.color[ATTR_MIDDLE] = COLOR_PAIR (COLR_RED); - attr.color[ATTR_LOW] = COLOR_PAIR (COLR_CYAN); - attr.color[ATTR_LOWEST] = COLOR_PAIR (COLR_YELLOW); - attr.color[ATTR_TRUE] = COLOR_PAIR (COLR_GREEN); - attr.color[ATTR_FALSE] = COLOR_PAIR (COLR_RED); + attr.color[ATTR_HIGHEST] = COLOR_PAIR(COLR_CUSTOM); + attr.color[ATTR_HIGH] = COLOR_PAIR(COLR_HIGH); + attr.color[ATTR_MIDDLE] = COLOR_PAIR(COLR_RED); + attr.color[ATTR_LOW] = COLOR_PAIR(COLR_CYAN); + attr.color[ATTR_LOWEST] = COLOR_PAIR(COLR_YELLOW); + attr.color[ATTR_TRUE] = COLOR_PAIR(COLR_GREEN); + attr.color[ATTR_FALSE] = COLOR_PAIR(COLR_RED); attr.nocolor[ATTR_HIGHEST] = A_BOLD; attr.nocolor[ATTR_HIGH] = A_REVERSE; @@ -214,458 +76,278 @@ custom_init_attr (void) } /* Apply window attribute */ -void -custom_apply_attr (WINDOW *win, int attr_num) +void custom_apply_attr(WINDOW * win, int attr_num) { if (colorize) - wattron (win, attr.color[attr_num]); + wattron(win, attr.color[attr_num]); else - wattron (win, attr.nocolor[attr_num]); + wattron(win, attr.nocolor[attr_num]); } /* Remove window attribute */ -void -custom_remove_attr (WINDOW *win, int attr_num) +void custom_remove_attr(WINDOW * win, int attr_num) { if (colorize) - wattroff (win, attr.color[attr_num]); + wattroff(win, attr.color[attr_num]); else - wattroff (win, attr.nocolor[attr_num]); -} - -/* Load the user configuration. */ -void -custom_load_conf (struct conf *conf, int background) -{ - FILE *data_file; - char *mesg_line1 = _("Failed to open config file"); - char *mesg_line2 = _("Press [ENTER] to continue"); - char buf[BUFSIZ], e_conf[BUFSIZ]; - enum conf_var var; - - data_file = fopen (path_conf, "r"); - if (data_file == NULL) - { - status_mesg (mesg_line1, mesg_line2); - wnoutrefresh (win[STA].p); - wins_doupdate (); - (void)keys_getch (win[STA].p); - } - var = CUSTOM_CONF_NOVARIABLE; - pthread_mutex_lock (&nbar.mutex); - for (;;) - { - if (fgets (buf, sizeof buf, data_file) == NULL) - { - break; - } - io_extract_data (e_conf, buf, sizeof buf); - - switch (var) - { - case CUSTOM_CONF_NOVARIABLE: - break; - case CUSTOM_CONF_AUTOSAVE: - conf->auto_save = fill_config_var (e_conf); - var = 0; - break; - case CUSTOM_CONF_PERIODICSAVE: - if (atoi (e_conf) < 0) - conf->periodic_save = 0; - else - conf->periodic_save = atoi (e_conf); - var = 0; - break; - case CUSTOM_CONF_CONFIRMQUIT: - conf->confirm_quit = fill_config_var (e_conf); - var = 0; - break; - case CUSTOM_CONF_CONFIRMDELETE: - conf->confirm_delete = fill_config_var (e_conf); - var = 0; - break; - case CUSTOM_CONF_SKIPSYSTEMDIALOGS: - conf->skip_system_dialogs = fill_config_var (e_conf); - var = 0; - break; - case CUSTOM_CONF_SKIPPROGRESSBAR: - conf->skip_progress_bar = fill_config_var (e_conf); - var = 0; - break; - case CUSTOM_CONF_CALENDAR_DEFAULTVIEW: - calendar_set_view (atoi (e_conf)); - var = 0; - break; - case CUSTOM_CONF_WEEKBEGINSONMONDAY: - if (fill_config_var (e_conf)) - calendar_set_first_day_of_week (MONDAY); - else - calendar_set_first_day_of_week (SUNDAY); - var = 0; - break; - case CUSTOM_CONF_COLORTHEME: - custom_load_color (e_conf, background); - var = 0; - break; - case CUSTOM_CONF_LAYOUT: - wins_set_layout (atoi (e_conf)); - var = 0; - break; - case CUSTOM_CONF_SBAR_WIDTH: - wins_set_sbar_width (atoi (e_conf)); - var = 0; - break; - case CUSTOM_CONF_NOTIFYBARSHOW: - nbar.show = fill_config_var (e_conf); - var = 0; - break; - case CUSTOM_CONF_NOTIFYBARDATE: - (void)strncpy (nbar.datefmt, e_conf, strlen (e_conf) + 1); - var = 0; - break; - case CUSTOM_CONF_NOTIFYBARCLOCK: - (void)strncpy (nbar.timefmt, e_conf, strlen (e_conf) + 1); - var = 0; - break; - case CUSTOM_CONF_NOTIFYBARWARNING: - nbar.cntdwn = atoi (e_conf); - var = 0; - break; - case CUSTOM_CONF_NOTIFYBARCOMMAND: - (void)strncpy (nbar.cmd, e_conf, strlen (e_conf) + 1); - var = 0; - break; - case CUSTOM_CONF_OUTPUTDATEFMT: - if (e_conf[0] != '\0') - (void)strncpy (conf->output_datefmt, e_conf, strlen (e_conf) + 1); - var = 0; - break; - case CUSTOM_CONF_INPUTDATEFMT: - conf->input_datefmt = atoi (e_conf); - if (conf->input_datefmt <= 0 || conf->input_datefmt >= DATE_FORMATS) - conf->input_datefmt = 1; - var = 0; - break; - case CUSTOM_CONF_DMON_ENABLE: - dmon.enable = fill_config_var (e_conf); - var = 0; - break; - case CUSTOM_CONF_DMON_LOG: - dmon.log = fill_config_var (e_conf); - var = 0; - break; - default: - EXIT (_("configuration variable unknown")); - /* NOTREACHED */ - } - - if (strncmp (e_conf, "auto_save=", 10) == 0) - var = CUSTOM_CONF_AUTOSAVE; - else if (strncmp (e_conf, "periodic_save=", 14) == 0) - var = CUSTOM_CONF_PERIODICSAVE; - else if (strncmp (e_conf, "confirm_quit=", 13) == 0) - var = CUSTOM_CONF_CONFIRMQUIT; - else if (strncmp (e_conf, "confirm_delete=", 15) == 0) - var = CUSTOM_CONF_CONFIRMDELETE; - else if (strncmp (e_conf, "skip_system_dialogs=", 20) == 0) - var = CUSTOM_CONF_SKIPSYSTEMDIALOGS; - else if (strncmp (e_conf, "skip_progress_bar=", 18) == 0) - var = CUSTOM_CONF_SKIPPROGRESSBAR; - else if (strncmp (e_conf, "calendar_default_view=", 22) == 0) - var = CUSTOM_CONF_CALENDAR_DEFAULTVIEW; - else if (strncmp (e_conf, "week_begins_on_monday=", 22) == 0) - var = CUSTOM_CONF_WEEKBEGINSONMONDAY; - else if (strncmp (e_conf, "color-theme=", 12) == 0) - var = CUSTOM_CONF_COLORTHEME; - else if (strncmp (e_conf, "layout=", 7) == 0) - var = CUSTOM_CONF_LAYOUT; - else if (strncmp (e_conf, "side-bar_width=", 15) == 0) - var = CUSTOM_CONF_SBAR_WIDTH; - else if (strncmp (e_conf, "notify-bar_show=", 16) == 0) - var = CUSTOM_CONF_NOTIFYBARSHOW; - else if (strncmp (e_conf, "notify-bar_date=", 16) == 0) - var = CUSTOM_CONF_NOTIFYBARDATE; - else if (strncmp (e_conf, "notify-bar_clock=", 17) == 0) - var = CUSTOM_CONF_NOTIFYBARCLOCK; - else if (strncmp (e_conf, "notify-bar_warning=", 19) == 0) - var = CUSTOM_CONF_NOTIFYBARWARNING; - else if (strncmp (e_conf, "notify-bar_command=", 19) == 0) - var = CUSTOM_CONF_NOTIFYBARCOMMAND; - else if (strncmp (e_conf, "output_datefmt=", 15) == 0) - var = CUSTOM_CONF_OUTPUTDATEFMT; - else if (strncmp (e_conf, "input_datefmt=", 14) == 0) - var = CUSTOM_CONF_INPUTDATEFMT; - else if (strncmp (e_conf, "notify-daemon_enable=", 21) == 0) - var = CUSTOM_CONF_DMON_ENABLE; - else if (strncmp (e_conf, "notify-daemon_log=", 18) == 0) - var = CUSTOM_CONF_DMON_LOG; - } - file_close (data_file, __FILE_POS__); - pthread_mutex_unlock (&nbar.mutex); + wattroff(win, attr.nocolor[attr_num]); } /* Draws the configuration bar */ -void -custom_config_bar (void) +void custom_config_bar(void) { const int SMLSPC = 2; const int SPC = 15; - custom_apply_attr (win[STA].p, ATTR_HIGHEST); - mvwprintw (win[STA].p, 0, 2, "Q"); - mvwprintw (win[STA].p, 1, 2, "G"); - mvwprintw (win[STA].p, 0, 2 + SPC, "L"); - mvwprintw (win[STA].p, 1, 2 + SPC, "S"); - mvwprintw (win[STA].p, 0, 2 + 2 * SPC, "C"); - mvwprintw (win[STA].p, 1, 2 + 2 * SPC, "N"); - mvwprintw (win[STA].p, 0, 2 + 3 * SPC, "K"); - custom_remove_attr (win[STA].p, ATTR_HIGHEST); - - mvwprintw (win[STA].p, 0, 2 + SMLSPC, _("Exit")); - mvwprintw (win[STA].p, 1, 2 + SMLSPC, _("General")); - mvwprintw (win[STA].p, 0, 2 + SPC + SMLSPC, _("Layout")); - mvwprintw (win[STA].p, 1, 2 + SPC + SMLSPC, _("Sidebar")); - mvwprintw (win[STA].p, 0, 2 + 2 * SPC + SMLSPC, _("Color")); - mvwprintw (win[STA].p, 1, 2 + 2 * SPC + SMLSPC, _("Notify")); - mvwprintw (win[STA].p, 0, 2 + 3 * SPC + SMLSPC, _("Keys")); - - wnoutrefresh (win[STA].p); - wmove (win[STA].p, 0, 0); - wins_doupdate (); + custom_apply_attr(win[STA].p, ATTR_HIGHEST); + mvwprintw(win[STA].p, 0, 2, "Q"); + mvwprintw(win[STA].p, 1, 2, "G"); + mvwprintw(win[STA].p, 0, 2 + SPC, "L"); + mvwprintw(win[STA].p, 1, 2 + SPC, "S"); + mvwprintw(win[STA].p, 0, 2 + 2 * SPC, "C"); + mvwprintw(win[STA].p, 1, 2 + 2 * SPC, "N"); + mvwprintw(win[STA].p, 0, 2 + 3 * SPC, "K"); + custom_remove_attr(win[STA].p, ATTR_HIGHEST); + + mvwprintw(win[STA].p, 0, 2 + SMLSPC, _("Exit")); + mvwprintw(win[STA].p, 1, 2 + SMLSPC, _("General")); + mvwprintw(win[STA].p, 0, 2 + SPC + SMLSPC, _("Layout")); + mvwprintw(win[STA].p, 1, 2 + SPC + SMLSPC, _("Sidebar")); + mvwprintw(win[STA].p, 0, 2 + 2 * SPC + SMLSPC, _("Color")); + mvwprintw(win[STA].p, 1, 2 + 2 * SPC + SMLSPC, _("Notify")); + mvwprintw(win[STA].p, 0, 2 + 3 * SPC + SMLSPC, _("Keys")); + + wnoutrefresh(win[STA].p); + wmove(win[STA].p, 0, 0); + wins_doupdate(); } -static void -layout_selection_bar (void) +static void layout_selection_bar(void) { - struct binding quit = {_("Exit"), KEY_GENERIC_QUIT}; - struct binding select = {_("Select"), KEY_GENERIC_SELECT}; - struct binding up = {_("Up"), KEY_MOVE_UP}; - struct binding down = {_("Down"), KEY_MOVE_DOWN}; - struct binding left = {_("Left"), KEY_MOVE_LEFT}; - struct binding right = {_("Right"), KEY_MOVE_RIGHT}; - struct binding help = {_("Help"), KEY_GENERIC_HELP}; - - struct binding *binding[] = {&quit, &select, &up, &down, &left, &right, &help}; - int binding_size = sizeof (binding) / sizeof (binding[0]); - - keys_display_bindings_bar (win[STA].p, binding, 0, binding_size); + struct binding quit = { _("Exit"), KEY_GENERIC_QUIT }; + struct binding select = { _("Select"), KEY_GENERIC_SELECT }; + struct binding up = { _("Up"), KEY_MOVE_UP }; + struct binding down = { _("Down"), KEY_MOVE_DOWN }; + struct binding left = { _("Left"), KEY_MOVE_LEFT }; + struct binding right = { _("Right"), KEY_MOVE_RIGHT }; + struct binding help = { _("Help"), KEY_GENERIC_HELP }; + + struct binding *bindings[] = { + &quit, &select, &up, &down, &left, &right, &help + }; + int bindings_size = sizeof(bindings) / sizeof(bindings[0]); + + keys_display_bindings_bar(win[STA].p, bindings, bindings_size, 0, + bindings_size, NULL); } #define NBLAYOUTS 8 #define LAYOUTSPERCOL 2 /* Used to display available layouts in layout configuration menu. */ -static void -display_layout_config (struct window *lwin, int mark, int cursor) +static void display_layout_config(struct window *lwin, int mark, int cursor) { #define CURSOR (32 | A_REVERSE) #define MARK 88 #define LAYOUTH 5 #define LAYOUTW 9 - char *box = "[ ]"; - const int BOXSIZ = strlen (box); + const char *box = "[ ]"; + const int BOXSIZ = strlen(box); const int NBCOLS = NBLAYOUTS / LAYOUTSPERCOL; const int COLSIZ = LAYOUTW + BOXSIZ + 1; const int XSPC = (lwin->w - NBCOLS * COLSIZ) / (NBCOLS + 1); const int XOFST = (lwin->w - NBCOLS * (XSPC + COLSIZ)) / 2; - const int YSPC = (lwin->h - 8 - LAYOUTSPERCOL * LAYOUTH) / (LAYOUTSPERCOL + 1); + const int YSPC = + (lwin->h - 8 - LAYOUTSPERCOL * LAYOUTH) / (LAYOUTSPERCOL + 1); const int YOFST = (lwin->h - LAYOUTSPERCOL * (YSPC + LAYOUTH)) / 2; - enum {YPOS, XPOS, NBPOS}; + enum { YPOS, XPOS, NBPOS }; int pos[NBLAYOUTS][NBPOS]; - char *layouts[LAYOUTH][NBLAYOUTS] = { - {"+---+---+", "+---+---+", "+---+---+", "+---+---+", "+---+---+", "+---+---+", "+---+---+", "+---+---+"}, - {"| | c |", "| | t |", "| c | |", "| t | |", "| | c |", "| | a |", "| c | |", "| a | |"}, - {"| a +---+", "| a +---+", "+---+ a |", "|---+ a |", "| t +---+", "| t +---+", "+---+ t |", "+---+ t |"}, - {"| | t |", "| | c |", "| t | |", "| c | |", "| | a |", "| | c |", "| a | |", "| c | |"}, - {"+---+---+", "+---+---+", "+---+---+", "+---+---+", "+---+---+", "+---+---+", "+---+---+", "+---+---+"} + const char *layouts[LAYOUTH][NBLAYOUTS] = { + {"+---+---+", "+---+---+", "+---+---+", "+---+---+", "+---+---+", + "+---+---+", "+---+---+", "+---+---+"}, + {"| | c |", "| | t |", "| c | |", "| t | |", "| | c |", + "| | a |", "| c | |", "| a | |"}, + {"| a +---+", "| a +---+", "+---+ a |", "|---+ a |", "| t +---+", + "| t +---+", "+---+ t |", "+---+ t |"}, + {"| | t |", "| | c |", "| t | |", "| c | |", "| | a |", + "| | c |", "| a | |", "| c | |"}, + {"+---+---+", "+---+---+", "+---+---+", "+---+---+", "+---+---+", + "+---+---+", "+---+---+", "+---+---+"} }; int i; - for (i = 0; i < NBLAYOUTS; i++) - { - pos[i][YPOS] = YOFST + (i % LAYOUTSPERCOL) * (YSPC + LAYOUTH); - pos[i][XPOS] = XOFST + (i / LAYOUTSPERCOL) * (XSPC + COLSIZ); - } + for (i = 0; i < NBLAYOUTS; i++) { + pos[i][YPOS] = YOFST + (i % LAYOUTSPERCOL) * (YSPC + LAYOUTH); + pos[i][XPOS] = XOFST + (i / LAYOUTSPERCOL) * (XSPC + COLSIZ); + } - for (i = 0; i < NBLAYOUTS; i++) - { - int j; - - mvwprintw (lwin->p, pos[i][YPOS] + 2, pos[i][XPOS], box); - if (i == mark) - custom_apply_attr (lwin->p, ATTR_HIGHEST); - for (j = 0; j < LAYOUTH; j++) - { - mvwprintw (lwin->p, pos[i][YPOS] + j, pos[i][XPOS] + BOXSIZ + 1, - layouts[j][i]); - } - if (i == mark) - custom_remove_attr (lwin->p, ATTR_HIGHEST); + for (i = 0; i < NBLAYOUTS; i++) { + int j; + + mvwprintw(lwin->p, pos[i][YPOS] + 2, pos[i][XPOS], box); + if (i == mark) + custom_apply_attr(lwin->p, ATTR_HIGHEST); + for (j = 0; j < LAYOUTH; j++) { + mvwprintw(lwin->p, pos[i][YPOS] + j, pos[i][XPOS] + BOXSIZ + 1, + layouts[j][i]); } - mvwaddch (lwin->p, pos[mark][YPOS] + 2, pos[mark][XPOS] + 1, MARK); - mvwaddch (lwin->p, pos[cursor][YPOS] + 2, pos[cursor][XPOS] + 1, CURSOR); - - layout_selection_bar (); - wnoutrefresh (win[STA].p); - wnoutrefresh (lwin->p); - wins_doupdate (); - if (notify_bar ()) - notify_update_bar (); + if (i == mark) + custom_remove_attr(lwin->p, ATTR_HIGHEST); + } + mvwaddch(lwin->p, pos[mark][YPOS] + 2, pos[mark][XPOS] + 1, MARK); + mvwaddch(lwin->p, pos[cursor][YPOS] + 2, pos[cursor][XPOS] + 1, CURSOR); + + layout_selection_bar(); + wnoutrefresh(win[STA].p); + wnoutrefresh(lwin->p); + wins_doupdate(); + if (notify_bar()) + notify_update_bar(); } /* Choose the layout */ -void -custom_layout_config (void) +void custom_layout_config(void) { struct scrollwin hwin; struct window conf_win; int ch, mark, cursor, need_reset; - char label[BUFSIZ]; - char *help_text = - _("With this configuration menu, one can choose where panels will be\n" - "displayed inside calcurse screen. \n" - "It is possible to choose between eight different configurations.\n" - "\nIn the configuration representations, letters correspond to:\n\n" - " 'c' -> calendar panel\n\n" - " 'a' -> appointment panel\n\n" - " 't' -> todo panel\n\n"); - - conf_win.p = (WINDOW *)0; - (void)snprintf (label, BUFSIZ, _("layout configuration")); - custom_confwin_init (&conf_win, label); - cursor = mark = wins_layout () - 1; - display_layout_config (&conf_win, mark, cursor); - clear (); - - while ((ch = keys_getch (win[STA].p)) != KEY_GENERIC_QUIT) - { - need_reset = 0; - switch (ch) - { - case KEY_GENERIC_HELP: - help_wins_init (&hwin, 0, 0, - (notify_bar ()) ? row - 3 : row - 2, col); - mvwprintw (hwin.pad.p, 1, 0, "%s", help_text); - hwin.total_lines = 7; - wins_scrollwin_display (&hwin); - wgetch (hwin.win.p); - wins_scrollwin_delete (&hwin); - need_reset = 1; - break; - case KEY_GENERIC_SELECT: - mark = cursor; - break; - case KEY_MOVE_DOWN: - if (cursor % LAYOUTSPERCOL < LAYOUTSPERCOL - 1) - cursor++; - break; - case KEY_MOVE_UP: - if (cursor % LAYOUTSPERCOL > 0) - cursor--; - break; - case KEY_MOVE_LEFT: - if (cursor >= LAYOUTSPERCOL) - cursor -= LAYOUTSPERCOL; - break; - case KEY_MOVE_RIGHT: - if (cursor < NBLAYOUTS - LAYOUTSPERCOL) - cursor += LAYOUTSPERCOL; - break; - case KEY_GENERIC_CANCEL: - need_reset = 1; - break; - } + const char *label = _("layout configuration"); + const char *help_text = + _("With this configuration menu, one can choose where panels will be\n" + "displayed inside calcurse screen. \n" + "It is possible to choose between eight different configurations.\n" + "\nIn the configuration representations, letters correspond to:\n\n" + " 'c' -> calendar panel\n\n" + " 'a' -> appointment panel\n\n" " 't' -> todo panel\n\n"); + + conf_win.p = NULL; + custom_confwin_init(&conf_win, label); + cursor = mark = wins_layout() - 1; + display_layout_config(&conf_win, mark, cursor); + clear(); + + while ((ch = keys_getch(win[STA].p, NULL)) != KEY_GENERIC_QUIT) { + need_reset = 0; + switch (ch) { + case KEY_GENERIC_HELP: + help_wins_init(&hwin, 0, 0, (notify_bar())? row - 3 : row - 2, col); + mvwprintw(hwin.pad.p, 1, 0, "%s", help_text); + hwin.total_lines = 7; + wins_scrollwin_display(&hwin); + wgetch(hwin.win.p); + wins_scrollwin_delete(&hwin); + need_reset = 1; + break; + case KEY_GENERIC_SELECT: + mark = cursor; + break; + case KEY_MOVE_DOWN: + if (cursor % LAYOUTSPERCOL < LAYOUTSPERCOL - 1) + cursor++; + break; + case KEY_MOVE_UP: + if (cursor % LAYOUTSPERCOL > 0) + cursor--; + break; + case KEY_MOVE_LEFT: + if (cursor >= LAYOUTSPERCOL) + cursor -= LAYOUTSPERCOL; + break; + case KEY_MOVE_RIGHT: + if (cursor < NBLAYOUTS - LAYOUTSPERCOL) + cursor += LAYOUTSPERCOL; + break; + case KEY_GENERIC_CANCEL: + need_reset = 1; + break; + } - if (resize) - { - resize = 0; - endwin (); - wins_refresh (); - curs_set (0); - need_reset = 1; - } + if (resize) { + resize = 0; + endwin(); + wins_refresh(); + curs_set(0); + need_reset = 1; + } - if (need_reset) - custom_confwin_init (&conf_win, label); + if (need_reset) + custom_confwin_init(&conf_win, label); - display_layout_config (&conf_win, mark, cursor); - } - wins_set_layout (mark + 1); - delwin (conf_win.p); + display_layout_config(&conf_win, mark, cursor); + } + wins_set_layout(mark + 1); + delwin(conf_win.p); } #undef NBLAYOUTS #undef LAYOUTSPERCOL /* Sidebar configuration screen. */ -void -custom_sidebar_config (void) +void custom_sidebar_config(void) { struct scrollwin hwin; - struct binding quit = {_("Exit"), KEY_GENERIC_QUIT}; - struct binding inc = {_("Width +"), KEY_MOVE_UP}; - struct binding dec = {_("Width -"), KEY_MOVE_DOWN}; - struct binding help = {_("Help"), KEY_GENERIC_HELP}; - struct binding *binding[] = {&inc, &dec, &help, &quit}; - char *help_text = - _("This configuration screen is used to change the width of the side bar.\n" - "The side bar is the part of the screen which contains two panels:\n" - "the calendar and, depending on the chosen layout, either the todo list\n" - "or the appointment list.\n\n" - "The side bar width can be up to 50% of the total screen width, but\n" - "can't be smaller than " TOSTRING(SBARMINWIDTH) " characters wide.\n\n"); - int ch, binding_size; - - binding_size = sizeof (binding) / sizeof (binding[0]); - - keys_display_bindings_bar (win[STA].p, binding, 0, binding_size); - wins_doupdate (); - - while ((ch = keys_getch (win[STA].p)) != KEY_GENERIC_QUIT) - { - switch (ch) - { - case KEY_MOVE_UP: - wins_sbar_winc (); - break; - case KEY_MOVE_DOWN: - wins_sbar_wdec (); - break; - case KEY_GENERIC_HELP: - help_wins_init (&hwin, 0, 0, - (notify_bar ()) ? row - 3 : row - 2, col); - mvwprintw (hwin.pad.p, 1, 0, "%s", help_text); - hwin.total_lines = 6; - wins_scrollwin_display (&hwin); - wgetch (hwin.win.p); - wins_scrollwin_delete (&hwin); - break; - case KEY_RESIZE: - break; - default: - continue; - } + struct binding quit = { _("Exit"), KEY_GENERIC_QUIT }; + struct binding inc = { _("Width +"), KEY_MOVE_UP }; + struct binding dec = { _("Width -"), KEY_MOVE_DOWN }; + struct binding help = { _("Help"), KEY_GENERIC_HELP }; + struct binding *bindings[] = { + &inc, &dec, &help, &quit + }; + const char *help_text = + _ + ("This configuration screen is used to change the width of the side bar.\n" + "The side bar is the part of the screen which contains two panels:\n" + "the calendar and, depending on the chosen layout, either the todo list\n" + "or the appointment list.\n\n" + "The side bar width can be up to 50% of the total screen width, but\n" + "can't be smaller than " TOSTRING(SBARMINWIDTH) " characters wide.\n\n"); + int ch, bindings_size; + + bindings_size = sizeof(bindings) / sizeof(bindings[0]); + + keys_display_bindings_bar(win[STA].p, bindings, bindings_size, 0, + bindings_size, NULL); + wins_doupdate(); + + while ((ch = keys_getch(win[STA].p, NULL)) != KEY_GENERIC_QUIT) { + switch (ch) { + case KEY_MOVE_UP: + wins_sbar_winc(); + break; + case KEY_MOVE_DOWN: + wins_sbar_wdec(); + break; + case KEY_GENERIC_HELP: + help_wins_init(&hwin, 0, 0, (notify_bar())? row - 3 : row - 2, col); + mvwprintw(hwin.pad.p, 1, 0, "%s", help_text); + hwin.total_lines = 6; + wins_scrollwin_display(&hwin); + wgetch(hwin.win.p); + wins_scrollwin_delete(&hwin); + break; + case KEY_RESIZE: + break; + default: + continue; + } - if (resize) - { - resize = 0; - wins_reset (); - } - else - { - wins_reinit_panels (); - wins_update_border (); - wins_update_panels (); - keys_display_bindings_bar (win[STA].p, binding, 0, binding_size); - wins_doupdate (); - } + if (resize) { + resize = 0; + wins_reset(); + } else { + wins_reinit_panels(); + wins_update_border(FLAG_ALL); + wins_update_panels(FLAG_ALL); + keys_display_bindings_bar(win[STA].p, bindings, bindings_size, 0, + bindings_size, NULL); + wins_doupdate(); } + } } -static void -set_confwin_attr (struct window *cwin) +static void set_confwin_attr(struct window *cwin) { - cwin->h = (notify_bar ())? row - 3 : row - 2; + cwin->h = (notify_bar())? row - 3 : row - 2; cwin->w = col; cwin->x = cwin->y = 0; } @@ -674,49 +356,45 @@ set_confwin_attr (struct window *cwin) * Create a configuration window and initialize status and notification bar * (useful in case of window resize). */ -void -custom_confwin_init (struct window *confwin, char *label) +void custom_confwin_init(struct window *confwin, const char *label) { - if (confwin->p) - { - erase_window_part (confwin->p, confwin->x, confwin->y, - confwin->x + confwin->w, confwin->y + confwin->h); - (void)delwin (confwin->p); - } - - wins_get_config (); - set_confwin_attr (confwin); - confwin->p = newwin (confwin->h, col, 0, 0); - box (confwin->p, 0, 0); - wins_show (confwin->p, label); - delwin (win[STA].p); - win[STA].p = newwin (win[STA].h, win[STA].w, win[STA].y, win[STA].x); - keypad (win[STA].p, TRUE); - if (notify_bar ()) - { - notify_reinit_bar (); - notify_update_bar (); - } + if (confwin->p) { + erase_window_part(confwin->p, confwin->x, confwin->y, + confwin->x + confwin->w, confwin->y + confwin->h); + delwin(confwin->p); + } + + wins_get_config(); + set_confwin_attr(confwin); + confwin->p = newwin(confwin->h, col, 0, 0); + box(confwin->p, 0, 0); + wins_show(confwin->p, label); + delwin(win[STA].p); + win[STA].p = newwin(win[STA].h, win[STA].w, win[STA].y, win[STA].x); + keypad(win[STA].p, TRUE); + if (notify_bar()) { + notify_reinit_bar(); + notify_update_bar(); + } } -static void -color_selection_bar (void) +static void color_selection_bar(void) { - struct binding quit = {_("Exit"), KEY_GENERIC_QUIT}; - struct binding select = {_("Select"), KEY_GENERIC_SELECT}; - struct binding nocolor = {_("No color"), KEY_GENERIC_CANCEL}; - struct binding up = {_("Up"), KEY_MOVE_UP}; - struct binding down = {_("Down"), KEY_MOVE_DOWN}; - struct binding left = {_("Left"), KEY_MOVE_LEFT}; - struct binding right = {_("Right"), KEY_MOVE_RIGHT}; - - - struct binding *binding[] = { + struct binding quit = { _("Exit"), KEY_GENERIC_QUIT }; + struct binding select = { _("Select"), KEY_GENERIC_SELECT }; + struct binding nocolor = { _("No color"), KEY_GENERIC_CANCEL }; + struct binding up = { _("Up"), KEY_MOVE_UP }; + struct binding down = { _("Down"), KEY_MOVE_DOWN }; + struct binding left = { _("Left"), KEY_MOVE_LEFT }; + struct binding right = { _("Right"), KEY_MOVE_RIGHT }; + + struct binding *bindings[] = { &quit, &nocolor, &up, &down, &left, &right, &select }; - int binding_size = sizeof (binding) / sizeof (binding[0]); + int bindings_size = sizeof(bindings) / sizeof(bindings[0]); - keys_display_bindings_bar (win[STA].p, binding, 0, binding_size); + keys_display_bindings_bar(win[STA].p, bindings, bindings_size, 0, + bindings_size, NULL); } /* @@ -724,8 +402,8 @@ color_selection_bar (void) * This is useful for window resizing. */ static void -display_color_config (struct window *cwin, int *mark_fore, int *mark_back, - int cursor, int theme_changed) +display_color_config(struct window *cwin, int *mark_fore, int *mark_back, + int cursor, int theme_changed) { #define SIZE (2 * (NBUSERCOLORS + 1)) #define DEFAULTCOLOR 255 @@ -733,21 +411,20 @@ display_color_config (struct window *cwin, int *mark_fore, int *mark_back, #define CURSOR (32 | A_REVERSE) #define MARK 88 - char *fore_txt = _("Foreground"); - char *back_txt = _("Background"); - char *default_txt = _("(terminal's default)"); - char *bar = " "; - char *box = "[ ]"; + const char *fore_txt = _("Foreground"); + const char *back_txt = _("Background"); + const char *default_txt = _("(terminal's default)"); + const char *bar = " "; + const char *box = "[ ]"; const unsigned Y = 3; const unsigned XOFST = 5; const unsigned YSPC = (cwin->h - 8) / (NBUSERCOLORS + 1); - const unsigned BARSIZ = strlen (bar); - const unsigned BOXSIZ = strlen (box); + const unsigned BARSIZ = strlen(bar); + const unsigned BOXSIZ = strlen(box); const unsigned XSPC = (cwin->w - 2 * BARSIZ - 2 * BOXSIZ - 6) / 3; const unsigned XFORE = XSPC; const unsigned XBACK = 2 * XSPC + BOXSIZ + XOFST + BARSIZ; - enum - { YPOS, XPOS, NBPOS }; + enum { YPOS, XPOS, NBPOS }; unsigned i; int pos[SIZE][NBPOS]; short colr_fore, colr_back; @@ -758,234 +435,168 @@ display_color_config (struct window *cwin, int *mark_fore, int *mark_back, COLR_MAGENTA, COLR_CYAN, COLR_DEFAULT }; - for (i = 0; i < NBUSERCOLORS + 1; i++) - { - pos[i][YPOS] = Y + YSPC * (i + 1); - pos[NBUSERCOLORS + i + 1][YPOS] = Y + YSPC * (i + 1); - pos[i][XPOS] = XFORE; - pos[NBUSERCOLORS + i + 1][XPOS] = XBACK; - } - - if (colorize) - { - if (theme_changed) - { - pair_content (colr[*mark_fore], &colr_fore, 0L); - if (colr_fore == 255) - colr_fore = -1; - pair_content (colr[*mark_back], &colr_back, 0L); - if (colr_back == 255) - colr_back = -1; - init_pair (COLR_CUSTOM, colr_fore, colr_back); - } + for (i = 0; i < NBUSERCOLORS + 1; i++) { + pos[i][YPOS] = Y + YSPC * (i + 1); + pos[NBUSERCOLORS + i + 1][YPOS] = Y + YSPC * (i + 1); + pos[i][XPOS] = XFORE; + pos[NBUSERCOLORS + i + 1][XPOS] = XBACK; + } + + if (colorize) { + if (theme_changed) { + pair_content(colr[*mark_fore], &colr_fore, 0L); + if (colr_fore == 255) + colr_fore = -1; + pair_content(colr[*mark_back], &colr_back, 0L); + if (colr_back == 255) + colr_back = -1; + init_pair(COLR_CUSTOM, colr_fore, colr_back); + } else { + /* Retrieve the actual color theme. */ + pair_content(COLR_CUSTOM, &colr_fore, &colr_back); + + if ((colr_fore == DEFAULTCOLOR) || (colr_fore == DEFAULTCOLOR_EXT)) + *mark_fore = NBUSERCOLORS; else - { - /* Retrieve the actual color theme. */ - pair_content (COLR_CUSTOM, &colr_fore, &colr_back); - - if ((colr_fore == DEFAULTCOLOR) || (colr_fore == DEFAULTCOLOR_EXT)) - *mark_fore = NBUSERCOLORS; - else - for (i = 0; i < NBUSERCOLORS + 1; i++) - if (colr_fore == colr[i]) - *mark_fore = i; + for (i = 0; i < NBUSERCOLORS + 1; i++) + if (colr_fore == colr[i]) + *mark_fore = i; - if ((colr_back == DEFAULTCOLOR) || (colr_back == DEFAULTCOLOR_EXT)) - *mark_back = SIZE - 1; - else - for (i = 0; i < NBUSERCOLORS + 1; i++) - if (colr_back == colr[NBUSERCOLORS + 1 + i]) - *mark_back = NBUSERCOLORS + 1 + i; - } + if ((colr_back == DEFAULTCOLOR) || (colr_back == DEFAULTCOLOR_EXT)) + *mark_back = SIZE - 1; + else + for (i = 0; i < NBUSERCOLORS + 1; i++) + if (colr_back == colr[NBUSERCOLORS + 1 + i]) + *mark_back = NBUSERCOLORS + 1 + i; } + } /* color boxes */ - for (i = 0; i < SIZE - 1; i++) - { - mvwprintw (cwin->p, pos[i][YPOS], pos[i][XPOS], box); - wattron (cwin->p, COLOR_PAIR (colr[i]) | A_REVERSE); - mvwprintw (cwin->p, pos[i][YPOS], pos[i][XPOS] + XOFST, bar); - wattroff (cwin->p, COLOR_PAIR (colr[i]) | A_REVERSE); - } + for (i = 0; i < SIZE - 1; i++) { + mvwprintw(cwin->p, pos[i][YPOS], pos[i][XPOS], box); + wattron(cwin->p, COLOR_PAIR(colr[i]) | A_REVERSE); + mvwprintw(cwin->p, pos[i][YPOS], pos[i][XPOS] + XOFST, bar); + wattroff(cwin->p, COLOR_PAIR(colr[i]) | A_REVERSE); + } /* Terminal's default color */ i = SIZE - 1; - mvwprintw (cwin->p, pos[i][YPOS], pos[i][XPOS], box); - wattron (cwin->p, COLOR_PAIR (colr[i])); - mvwprintw (cwin->p, pos[i][YPOS], pos[i][XPOS] + XOFST, bar); - wattroff (cwin->p, COLOR_PAIR (colr[i])); - mvwprintw (cwin->p, pos[NBUSERCOLORS][YPOS] + 1, - pos[NBUSERCOLORS][XPOS] + XOFST, default_txt); - mvwprintw (cwin->p, pos[SIZE - 1][YPOS] + 1, - pos[SIZE - 1][XPOS] + XOFST, default_txt); - - custom_apply_attr (cwin->p, ATTR_HIGHEST); - mvwprintw (cwin->p, Y, XFORE + XOFST, fore_txt); - mvwprintw (cwin->p, Y, XBACK + XOFST, back_txt); - custom_remove_attr (cwin->p, ATTR_HIGHEST); - - if (colorize) - { - mvwaddch (cwin->p, pos[*mark_fore][YPOS], - pos[*mark_fore][XPOS] + 1, MARK); - mvwaddch (cwin->p, pos[*mark_back][YPOS], - pos[*mark_back][XPOS] + 1, MARK); - } - - mvwaddch (cwin->p, pos[cursor][YPOS], pos[cursor][XPOS] + 1, CURSOR); - color_selection_bar (); - wnoutrefresh (win[STA].p); - wnoutrefresh (cwin->p); - wins_doupdate (); - if (notify_bar ()) - notify_update_bar (); + mvwprintw(cwin->p, pos[i][YPOS], pos[i][XPOS], box); + wattron(cwin->p, COLOR_PAIR(colr[i])); + mvwprintw(cwin->p, pos[i][YPOS], pos[i][XPOS] + XOFST, bar); + wattroff(cwin->p, COLOR_PAIR(colr[i])); + mvwprintw(cwin->p, pos[NBUSERCOLORS][YPOS] + 1, + pos[NBUSERCOLORS][XPOS] + XOFST, default_txt); + mvwprintw(cwin->p, pos[SIZE - 1][YPOS] + 1, + pos[SIZE - 1][XPOS] + XOFST, default_txt); + + custom_apply_attr(cwin->p, ATTR_HIGHEST); + mvwprintw(cwin->p, Y, XFORE + XOFST, fore_txt); + mvwprintw(cwin->p, Y, XBACK + XOFST, back_txt); + custom_remove_attr(cwin->p, ATTR_HIGHEST); + + if (colorize) { + mvwaddch(cwin->p, pos[*mark_fore][YPOS], pos[*mark_fore][XPOS] + 1, MARK); + mvwaddch(cwin->p, pos[*mark_back][YPOS], pos[*mark_back][XPOS] + 1, MARK); + } + + mvwaddch(cwin->p, pos[cursor][YPOS], pos[cursor][XPOS] + 1, CURSOR); + color_selection_bar(); + wnoutrefresh(win[STA].p); + wnoutrefresh(cwin->p); + wins_doupdate(); + if (notify_bar()) + notify_update_bar(); } /* Color theme configuration. */ -void -custom_color_config (void) +void custom_color_config(void) { struct window conf_win; int ch, cursor, need_reset, theme_changed; int mark_fore, mark_back; - char label[BUFSIZ]; + const char *label = _("color theme"); conf_win.p = 0; - (void)snprintf (label, BUFSIZ, _("color theme")); - custom_confwin_init (&conf_win, label); + custom_confwin_init(&conf_win, label); mark_fore = NBUSERCOLORS; mark_back = SIZE - 1; cursor = 0; theme_changed = 0; - display_color_config (&conf_win, &mark_fore, &mark_back, cursor, theme_changed); - clear (); - - while ((ch = keys_getch (win[STA].p)) != KEY_GENERIC_QUIT) - { - need_reset = 0; - theme_changed = 0; - - switch (ch) - { - case KEY_GENERIC_SELECT: - colorize = 1; - need_reset = 1; - theme_changed = 1; - if (cursor > NBUSERCOLORS) - mark_back = cursor; - else - mark_fore = cursor; - break; - - case KEY_MOVE_DOWN: - if (cursor < SIZE - 1) - ++cursor; - break; - - case KEY_MOVE_UP: - if (cursor > 0) - --cursor; - break; - - case KEY_MOVE_LEFT: - if (cursor > NBUSERCOLORS) - cursor -= (NBUSERCOLORS + 1); - break; - - case KEY_MOVE_RIGHT: - if (cursor <= NBUSERCOLORS) - cursor += (NBUSERCOLORS + 1); - break; - - case KEY_GENERIC_CANCEL: - colorize = 0; - need_reset = 1; - break; - } - - if (resize) - { - resize = 0; - endwin (); - wins_refresh (); - curs_set (0); - need_reset = 1; - } - - if (need_reset) - custom_confwin_init (&conf_win, label); - - display_color_config (&conf_win, &mark_fore, &mark_back, cursor, - theme_changed); + display_color_config(&conf_win, &mark_fore, &mark_back, cursor, + theme_changed); + clear(); + + while ((ch = keys_getch(win[STA].p, NULL)) != KEY_GENERIC_QUIT) { + need_reset = 0; + theme_changed = 0; + + switch (ch) { + case KEY_GENERIC_SELECT: + colorize = 1; + need_reset = 1; + theme_changed = 1; + if (cursor > NBUSERCOLORS) + mark_back = cursor; + else + mark_fore = cursor; + break; + + case KEY_MOVE_DOWN: + if (cursor < SIZE - 1) + ++cursor; + break; + + case KEY_MOVE_UP: + if (cursor > 0) + --cursor; + break; + + case KEY_MOVE_LEFT: + if (cursor > NBUSERCOLORS) + cursor -= (NBUSERCOLORS + 1); + break; + + case KEY_MOVE_RIGHT: + if (cursor <= NBUSERCOLORS) + cursor += (NBUSERCOLORS + 1); + break; + + case KEY_GENERIC_CANCEL: + colorize = 0; + need_reset = 1; + break; } - delwin (conf_win.p); -} -/* - * Return a string defining the color theme in the form: - * foreground color 'on' background color - * in order to dump this data in the configuration file. - * Color numbers follow the ncurses library definitions. - * If ncurses library was compiled with --enable-ext-funcs, - * then default color is -1. - */ -void -custom_color_theme_name (char *theme_name) -{ -#define MAXCOLORS 8 -#define NBCOLORS 2 -#define DEFAULTCOLOR 255 -#define DEFAULTCOLOR_EXT -1 + if (resize) { + resize = 0; + endwin(); + wins_refresh(); + curs_set(0); + need_reset = 1; + } - int i; - short color[NBCOLORS]; - char *color_name[NBCOLORS]; - char *default_color = "default"; - char *name[MAXCOLORS] = { - "black", - "red", - "green", - "yellow", - "blue", - "magenta", - "cyan", - "white" - }; + if (need_reset) + custom_confwin_init(&conf_win, label); - if (!colorize) - (void)snprintf (theme_name, BUFSIZ, "0"); - else - { - pair_content (COLR_CUSTOM, &color[0], &color[1]); - for (i = 0; i < NBCOLORS; i++) - { - if ((color[i] == DEFAULTCOLOR) || (color[i] == DEFAULTCOLOR_EXT)) - color_name[i] = default_color; - else if (color[i] >= 0 && color[i] <= MAXCOLORS) - color_name[i] = name[color[i]]; - else - { - EXIT (_("unknown color")); - /* NOTREACHED */ - } - } - (void)snprintf (theme_name, BUFSIZ, "%s on %s", color_name[0], - color_name[1]); - } + display_color_config(&conf_win, &mark_fore, &mark_back, cursor, + theme_changed); + } + delwin(conf_win.p); } /* Prints the general options. */ -static int -print_general_options (WINDOW *win, struct conf *conf) +static int print_general_options(WINDOW * win) { enum { AUTO_SAVE, + AUTO_GC, PERIODIC_SAVE, CONFIRM_QUIT, CONFIRM_DELETE, - SKIP_SYSTEM_DIAGS, - SKIP_PROGRESS_BAR, - WEEK_BEGINS_MONDAY, + SYSTEM_DIAGS, + PROGRESS_BAR, + FIRST_DAY_OF_WEEK, OUTPUT_DATE_FMT, INPUT_DATE_FMT, NB_OPTIONS @@ -994,93 +605,99 @@ print_general_options (WINDOW *win, struct conf *conf) const int YOFF = 3; int y; char *opt[NB_OPTIONS] = { - _("auto_save = "), - _("periodic_save = "), - _("confirm_quit = "), - _("confirm_delete = "), - _("skip_system_dialogs = "), - _("skip_progress_bar = "), - _("week_begins_on_monday = "), - _("output_datefmt = "), - _("input_datefmt = ") + _("general.autosave = "), + _("general.autogc = "), + _("general.periodicsave = "), + _("general.confirmquit = "), + _("general.confirmdelete = "), + _("general.systemdialogs = "), + _("general.progressbar = "), + _("general.firstdayofweek = "), + _("format.outputdate = "), + _("format.inputdate = ") }; y = 0; - mvwprintw (win, y, XPOS, "[1] %s ", opt[AUTO_SAVE]); - print_bool_option_incolor (win, conf->auto_save, y, - XPOS + 4 + strlen (opt[AUTO_SAVE])); - mvwprintw (win, y + 1, XPOS, - _("(if set to YES, automatic save is done when quitting)")); + mvwprintw(win, y, XPOS, "[1] %s ", opt[AUTO_SAVE]); + print_bool_option_incolor(win, conf.auto_save, y, + XPOS + 4 + strlen(opt[AUTO_SAVE])); + mvwprintw(win, y + 1, XPOS, + _("(if set to YES, automatic save is done when quitting)")); y += YOFF; - mvwprintw (win, y, XPOS, "[2] %s ", opt[PERIODIC_SAVE]); - custom_apply_attr (win, ATTR_HIGHEST); - mvwprintw (win, y, XPOS + 4 + strlen (opt[PERIODIC_SAVE]), "%d", - conf->periodic_save); - custom_remove_attr (win, ATTR_HIGHEST); - mvwprintw (win, y + 1, XPOS, - _("(if not null, automatically save data every 'periodic_save' " - "minutes)")); + mvwprintw(win, y, XPOS, "[2] %s ", opt[AUTO_GC]); + print_bool_option_incolor(win, conf.auto_gc, y, + XPOS + 4 + strlen(opt[AUTO_GC])); + mvwprintw(win, y + 1, XPOS, _("(run the garbage collector when quitting)")); y += YOFF; - mvwprintw (win, y, XPOS, "[3] %s ", opt[CONFIRM_QUIT]); - print_bool_option_incolor (win, conf->confirm_quit, y, - XPOS + 4 + strlen (opt[CONFIRM_QUIT])); - mvwprintw (win, y + 1, XPOS, - _("(if set to YES, confirmation is required before quitting)")); + mvwprintw(win, y, XPOS, "[3] %s ", opt[PERIODIC_SAVE]); + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, y, XPOS + 4 + strlen(opt[PERIODIC_SAVE]), "%d", + conf.periodic_save); + custom_remove_attr(win, ATTR_HIGHEST); + mvwprintw(win, y + 1, XPOS, + _("(if not null, automatically save data every 'periodic_save' " + "minutes)")); y += YOFF; - mvwprintw (win, y, XPOS, "[4] %s ", opt[CONFIRM_DELETE]); - print_bool_option_incolor (win, conf->confirm_delete, y, - XPOS + 4 + strlen (opt[CONFIRM_DELETE])); - mvwprintw (win, y + 1, XPOS, - _("(if set to YES, confirmation is required " - "before deleting an event)")); + mvwprintw(win, y, XPOS, "[4] %s ", opt[CONFIRM_QUIT]); + print_bool_option_incolor(win, conf.confirm_quit, y, + XPOS + 4 + strlen(opt[CONFIRM_QUIT])); + mvwprintw(win, y + 1, XPOS, + _("(if set to YES, confirmation is required before quitting)")); y += YOFF; - mvwprintw (win, y, XPOS, "[5] %s ", opt[SKIP_SYSTEM_DIAGS]); - print_bool_option_incolor (win, conf->skip_system_dialogs, y, - XPOS + 4 + strlen (opt[SKIP_SYSTEM_DIAGS])); - mvwprintw (win, y + 1, XPOS, - _("(if set to YES, messages about loaded " - "and saved data will not be displayed)")); + mvwprintw(win, y, XPOS, "[5] %s ", opt[CONFIRM_DELETE]); + print_bool_option_incolor(win, conf.confirm_delete, y, + XPOS + 4 + strlen(opt[CONFIRM_DELETE])); + mvwprintw(win, y + 1, XPOS, + _("(if set to YES, confirmation is required " + "before deleting an event)")); y += YOFF; - mvwprintw (win, y, XPOS, "[6] %s ", opt[SKIP_PROGRESS_BAR]); - print_bool_option_incolor (win, conf->skip_progress_bar, y, - XPOS + 4 + strlen (opt[SKIP_PROGRESS_BAR])); - mvwprintw (win, y + 1, XPOS, - _("(if set to YES, progress bar will not be displayed " - "when saving data)")); + mvwprintw(win, y, XPOS, "[6] %s ", opt[SYSTEM_DIAGS]); + print_bool_option_incolor(win, conf.system_dialogs, y, + XPOS + 4 + strlen(opt[SYSTEM_DIAGS])); + mvwprintw(win, y + 1, XPOS, + _("(if set to YES, messages about loaded " + "and saved data will be displayed)")); y += YOFF; - mvwprintw (win, y, XPOS, "[7] %s ", opt[WEEK_BEGINS_MONDAY]); - print_bool_option_incolor (win, calendar_week_begins_on_monday (), y, - XPOS + 4 + strlen (opt[WEEK_BEGINS_MONDAY])); - mvwprintw (win, y + 1, XPOS, - _("(if set to YES, monday is the first day of the week, " - "else it is sunday)")); + mvwprintw(win, y, XPOS, "[7] %s ", opt[PROGRESS_BAR]); + print_bool_option_incolor(win, conf.progress_bar, y, + XPOS + 4 + strlen(opt[PROGRESS_BAR])); + mvwprintw(win, y + 1, XPOS, + _("(if set to YES, progress bar will be displayed " + "when saving data)")); y += YOFF; - mvwprintw (win, y, XPOS, "[8] %s ", opt[OUTPUT_DATE_FMT]); - custom_apply_attr (win, ATTR_HIGHEST); - mvwprintw (win, y, XPOS + 4 + strlen (opt[OUTPUT_DATE_FMT]), "%s", - conf->output_datefmt); - custom_remove_attr (win, ATTR_HIGHEST); - mvwprintw (win, y + 1, XPOS, - _("(Format of the date to be displayed in non-interactive mode)")); + mvwprintw(win, y, XPOS, "[8] %s ", opt[FIRST_DAY_OF_WEEK]); + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, y, XPOS + 4 + strlen(opt[FIRST_DAY_OF_WEEK]), "%s", + calendar_week_begins_on_monday()? _("Monday") : _("Sunday")); + custom_remove_attr(win, ATTR_HIGHEST); + mvwprintw(win, y + 1, XPOS, + _("(specifies the first day of week in the calendar view)")); y += YOFF; - mvwprintw (win, y, XPOS, "[9] %s ", opt[INPUT_DATE_FMT]); - custom_apply_attr (win, ATTR_HIGHEST); - mvwprintw (win, y, XPOS + 4 + strlen (opt[INPUT_DATE_FMT]), "%d", - conf->input_datefmt); - custom_remove_attr (win, ATTR_HIGHEST); - mvwprintw (win, y + 1, XPOS, _("(Format to be used when entering a date: ")); - mvwprintw (win, y + 2, XPOS, - _(" (1)mm/dd/yyyy (2)dd/mm/yyyy (3)yyyy/mm/dd (4)yyyy-mm-dd)")); + mvwprintw(win, y, XPOS, "[9] %s ", opt[OUTPUT_DATE_FMT]); + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, y, XPOS + 4 + strlen(opt[OUTPUT_DATE_FMT]), "%s", + conf.output_datefmt); + custom_remove_attr(win, ATTR_HIGHEST); + mvwprintw(win, y + 1, XPOS, + _("(Format of the date to be displayed in non-interactive mode)")); + y += YOFF; + mvwprintw(win, y, XPOS, "[0] %s ", opt[INPUT_DATE_FMT]); + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, y, XPOS + 4 + strlen(opt[INPUT_DATE_FMT]), "%d", + conf.input_datefmt); + custom_remove_attr(win, ATTR_HIGHEST); + mvwprintw(win, y + 1, XPOS, _("(Format to be used when entering a date: ")); + mvwprintw(win, y + 2, XPOS, + _(" (1)mm/dd/yyyy (2)dd/mm/yyyy (3)yyyy/mm/dd (4)yyyy-mm-dd)")); return y + YOFF; } -void -custom_set_swsiz (struct scrollwin *sw) +void custom_set_swsiz(struct scrollwin *sw) { sw->win.x = 0; sw->win.y = 0; - sw->win.h = (notify_bar ()) ? row - 3 : row - 2; + sw->win.h = (notify_bar())? row - 3 : row - 2; sw->win.w = col; sw->pad.x = 1; @@ -1090,143 +707,132 @@ custom_set_swsiz (struct scrollwin *sw) } /* General configuration. */ -void -custom_general_config (struct conf *conf) +void custom_general_config(void) { struct scrollwin cwin; - char *number_str = - _("Enter an option number to change its value"); - char *keys = - _("(Press '^P' or '^N' to move up or down, 'Q' to quit)"); - char *output_datefmt_str = - _("Enter the date format (see 'man 3 strftime' for possible formats) "); - char *input_datefmt_str = - _("Enter the date format (1)mm/dd/yyyy (2)dd/mm/yyyy (3)yyyy/mm/dd " - "(4)yyyy-mm-dd"); - char *periodic_save_str = - _("Enter the delay, in minutes, between automatic saves (0 to disable) "); + const char *number_str = _("Enter an option number to change its value"); + const char *keys = _("(Press '^P' or '^N' to move up or down, 'Q' to quit)"); + const char *output_datefmt_str = + _("Enter the date format (see 'man 3 strftime' for possible formats) "); + const char *input_datefmt_str = + _("Enter the date format (1)mm/dd/yyyy (2)dd/mm/yyyy (3)yyyy/mm/dd " + "(4)yyyy-mm-dd"); + const char *periodic_save_str = + _("Enter the delay, in minutes, between automatic saves (0 to disable) "); int ch; char *buf; - clear (); - custom_set_swsiz (&cwin); - (void)snprintf (cwin.label, BUFSIZ, _("general options")); - wins_scrollwin_init (&cwin); - wins_show (cwin.win.p, cwin.label); - status_mesg (number_str, keys); - cwin.total_lines = print_general_options (cwin.pad.p, conf); - wins_scrollwin_display (&cwin); - - buf = mem_malloc (BUFSIZ); - while ((ch = wgetch (win[STA].p)) != 'q') - { - buf[0] = '\0'; - - switch (ch) - { - case CTRL ('N'): - wins_scrollwin_down (&cwin, 1); - break; - case CTRL ('P'): - wins_scrollwin_up (&cwin, 1); - break; - case '1': - conf->auto_save = !conf->auto_save; - break; - case '2': - status_mesg (periodic_save_str, ""); - if (updatestring (win[STA].p, &buf, 0, 1) == 0) - { - int val = atoi (buf); - if (val >= 0) - conf->periodic_save = val; - if (conf->periodic_save > 0) - io_start_psave_thread (conf); - else if (conf->periodic_save == 0) - io_stop_psave_thread (); - } - status_mesg (number_str, keys); - break; - case '3': - conf->confirm_quit = !conf->confirm_quit; - break; - case '4': - conf->confirm_delete = !conf->confirm_delete; - break; - case '5': - conf->skip_system_dialogs = !conf->skip_system_dialogs; - break; - case '6': - conf->skip_progress_bar = !conf->skip_progress_bar; - break; - case '7': - calendar_change_first_day_of_week (); - break; - case '8': - status_mesg (output_datefmt_str, ""); - (void)strncpy (buf, conf->output_datefmt, - strlen (conf->output_datefmt) + 1); - if (updatestring (win[STA].p, &buf, 0, 1) == 0) - { - (void)strncpy (conf->output_datefmt, buf, strlen (buf) + 1); - } - status_mesg (number_str, keys); - break; - case '9': - status_mesg (input_datefmt_str, ""); - if (updatestring (win[STA].p, &buf, 0, 1) == 0) - { - int val = atoi (buf); - if (val > 0 && val <= DATE_FORMATS) - conf->input_datefmt = val; - } - status_mesg (number_str, keys); - break; - } - - if (resize) - { - resize = 0; - wins_reset (); - wins_scrollwin_delete (&cwin); - custom_set_swsiz (&cwin); - wins_scrollwin_init (&cwin); - wins_show (cwin.win.p, cwin.label); - cwin.first_visible_line = 0; - delwin (win[STA].p); - win[STA].p = newwin (win[STA].h, win[STA].w, win[STA].y, - win[STA].x); - keypad (win[STA].p, TRUE); - if (notify_bar ()) - { - notify_reinit_bar (); - notify_update_bar (); - } - } + clear(); + custom_set_swsiz(&cwin); + cwin.label = _("general options"); + wins_scrollwin_init(&cwin); + wins_show(cwin.win.p, cwin.label); + status_mesg(number_str, keys); + cwin.total_lines = print_general_options(cwin.pad.p); + wins_scrollwin_display(&cwin); + + buf = mem_malloc(BUFSIZ); + while ((ch = wgetch(win[STA].p)) != 'q') { + buf[0] = '\0'; + + switch (ch) { + case CTRL('N'): + wins_scrollwin_down(&cwin, 1); + break; + case CTRL('P'): + wins_scrollwin_up(&cwin, 1); + break; + case '1': + conf.auto_save = !conf.auto_save; + break; + case '2': + conf.auto_gc = !conf.auto_gc; + break; + case '3': + status_mesg(periodic_save_str, ""); + if (updatestring(win[STA].p, &buf, 0, 1) == 0) { + int val = atoi(buf); + if (val >= 0) + conf.periodic_save = val; + if (conf.periodic_save > 0) + io_start_psave_thread(); + else if (conf.periodic_save == 0) + io_stop_psave_thread(); + } + status_mesg(number_str, keys); + break; + case '4': + conf.confirm_quit = !conf.confirm_quit; + break; + case '5': + conf.confirm_delete = !conf.confirm_delete; + break; + case '6': + conf.system_dialogs = !conf.system_dialogs; + break; + case '7': + conf.progress_bar = !conf.progress_bar; + break; + case '8': + calendar_change_first_day_of_week(); + break; + case '9': + status_mesg(output_datefmt_str, ""); + strncpy(buf, conf.output_datefmt, strlen(conf.output_datefmt) + 1); + if (updatestring(win[STA].p, &buf, 0, 1) == 0) { + strncpy(conf.output_datefmt, buf, strlen(buf) + 1); + } + status_mesg(number_str, keys); + break; + case '0': + status_mesg(input_datefmt_str, ""); + if (updatestring(win[STA].p, &buf, 0, 1) == 0) { + int val = atoi(buf); + if (val > 0 && val <= DATE_FORMATS) + conf.input_datefmt = val; + } + status_mesg(number_str, keys); + break; + } - status_mesg (number_str, keys); - cwin.total_lines = print_general_options (cwin.pad.p, conf); - wins_scrollwin_display (&cwin); + if (resize) { + resize = 0; + wins_reset(); + wins_scrollwin_delete(&cwin); + custom_set_swsiz(&cwin); + wins_scrollwin_init(&cwin); + wins_show(cwin.win.p, cwin.label); + cwin.first_visible_line = 0; + delwin(win[STA].p); + win[STA].p = newwin(win[STA].h, win[STA].w, win[STA].y, win[STA].x); + keypad(win[STA].p, TRUE); + if (notify_bar()) { + notify_reinit_bar(); + notify_update_bar(); + } } - mem_free (buf); - wins_scrollwin_delete (&cwin); -} + status_mesg(number_str, keys); + cwin.total_lines = print_general_options(cwin.pad.p); + wins_scrollwin_display(&cwin); + } + mem_free(buf); + wins_scrollwin_delete(&cwin); +} static void -print_key_incolor (WINDOW *win, char *option, int pos_y, int pos_x) +print_key_incolor(WINDOW * win, const char *option, int pos_y, int pos_x) { const int color = ATTR_HIGHEST; - RETURN_IF (!option, _("Undefined option!")); - custom_apply_attr (win, color); - mvwprintw (win, pos_y, pos_x, "%s ", option); - custom_remove_attr (win, color); - wnoutrefresh (win); + RETURN_IF(!option, _("Undefined option!")); + custom_apply_attr(win, color); + mvwprintw(win, pos_y, pos_x, "%s ", option); + custom_remove_attr(win, color); } static int -print_keys_bindings (WINDOW *win, int selected_row, int selected_elm, int yoff) +print_keys_bindings(WINDOW * win, int selected_row, int selected_elm, int yoff) { const int XPOS = 1; const int EQUALPOS = 23; @@ -1234,208 +840,242 @@ print_keys_bindings (WINDOW *win, int selected_row, int selected_elm, int yoff) int noelm, action, y; noelm = y = 0; - for (action = 0; action < NBKEYS; action++) - { - char actionstr[BUFSIZ]; - int nbkeys; - - nbkeys = keys_action_count_keys (action); - (void)snprintf (actionstr, BUFSIZ, "%s", keys_get_label (action)); - if (action == selected_row) - custom_apply_attr (win, ATTR_HIGHEST); - mvwprintw (win, y, XPOS, "%s ", actionstr); - mvwprintw (win, y, EQUALPOS, "="); - if (nbkeys == 0) - mvwprintw (win, y, KEYPOS, _("undefined")); - if (action == selected_row) - custom_remove_attr (win, ATTR_HIGHEST); - if (nbkeys > 0) - { - if (action == selected_row) - { - char *key; - int pos; - - pos = KEYPOS; - while ((key = keys_action_nkey (action, noelm)) != NULL) - { - if (noelm == selected_elm) - print_key_incolor (win, key, y, pos); - else - mvwprintw (win, y, pos, "%s ", key); - noelm++; - pos += strlen (key) + 1; - } - } + for (action = 0; action < NBKEYS; action++) { + char actionstr[BUFSIZ]; + int nbkeys; + + nbkeys = keys_action_count_keys(action); + snprintf(actionstr, BUFSIZ, "%s", keys_get_label(action)); + if (action == selected_row) + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, y, XPOS, "%s ", actionstr); + mvwprintw(win, y, EQUALPOS, "="); + if (nbkeys == 0) + mvwprintw(win, y, KEYPOS, _("undefined")); + if (action == selected_row) + custom_remove_attr(win, ATTR_HIGHEST); + if (nbkeys > 0) { + if (action == selected_row) { + const char *key; + int pos; + + pos = KEYPOS; + while ((key = keys_action_nkey(action, noelm)) != NULL) { + if (noelm == selected_elm) + print_key_incolor(win, key, y, pos); else - { - mvwprintw (win, y, KEYPOS, "%s", keys_action_allkeys (action)); - } + mvwprintw(win, y, pos, "%s ", key); + noelm++; + pos += strlen(key) + 1; } - y += yoff; + } else { + mvwprintw(win, y, KEYPOS, "%s", keys_action_allkeys(action)); + } } + y += yoff; + } return noelm; } -static void -custom_keys_config_bar (void) +static void custom_keys_config_bar(void) { - struct binding quit = {_("Exit"), KEY_GENERIC_QUIT}; - struct binding info = {_("Key info"), KEY_GENERIC_HELP}; - struct binding add = {_("Add key"), KEY_ADD_ITEM}; - struct binding del = {_("Del key"), KEY_DEL_ITEM}; - struct binding up = {_("Up"), KEY_MOVE_UP}; - struct binding down = {_("Down"), KEY_MOVE_DOWN}; - struct binding left = {_("Prev Key"), KEY_MOVE_LEFT}; - struct binding right = {_("Next Key"), KEY_MOVE_RIGHT}; - - struct binding *binding[] = { + struct binding quit = { _("Exit"), KEY_GENERIC_QUIT }; + struct binding info = { _("Key info"), KEY_GENERIC_HELP }; + struct binding add = { _("Add key"), KEY_ADD_ITEM }; + struct binding del = { _("Del key"), KEY_DEL_ITEM }; + struct binding up = { _("Up"), KEY_MOVE_UP }; + struct binding down = { _("Down"), KEY_MOVE_DOWN }; + struct binding left = { _("Prev Key"), KEY_MOVE_LEFT }; + struct binding right = { _("Next Key"), KEY_MOVE_RIGHT }; + + struct binding *bindings[] = { &quit, &info, &add, &del, &up, &down, &left, &right }; - int binding_size = sizeof (binding) / sizeof (binding[0]); + int bindings_size = sizeof(bindings) / sizeof(bindings[0]); - keys_display_bindings_bar (win[STA].p, binding, 0, binding_size); + keys_display_bindings_bar(win[STA].p, bindings, bindings_size, 0, + bindings_size, NULL); } -void -custom_keys_config (void) +void custom_keys_config(void) { struct scrollwin kwin; int selrow, selelm, firstrow, lastrow, nbrowelm, nbdisplayed; int keyval, used, not_recognized; - char *keystr; + const char *keystr; WINDOW *grabwin; const int LINESPERKEY = 2; const int LABELLINES = 3; - clear (); - custom_set_swsiz (&kwin); + clear(); + custom_set_swsiz(&kwin); nbdisplayed = (kwin.win.h - LABELLINES) / LINESPERKEY; - (void)snprintf (kwin.label, BUFSIZ, _("keys configuration")); - wins_scrollwin_init (&kwin); - wins_show (kwin.win.p, kwin.label); - custom_keys_config_bar (); + kwin.label = _("keys configuration"); + wins_scrollwin_init(&kwin); + wins_show(kwin.win.p, kwin.label); + custom_keys_config_bar(); selrow = selelm = 0; - nbrowelm = print_keys_bindings (kwin.pad.p, selrow, selelm, LINESPERKEY); + nbrowelm = print_keys_bindings(kwin.pad.p, selrow, selelm, LINESPERKEY); kwin.total_lines = NBKEYS * LINESPERKEY; - wins_scrollwin_display (&kwin); + wins_scrollwin_display(&kwin); firstrow = 0; lastrow = firstrow + nbdisplayed - 1; - for (;;) - { - int ch; - - ch = keys_getch (win[STA].p); - switch (ch) - { - case KEY_MOVE_UP: - if (selrow > 0) - { - selrow--; - selelm = 0; - if (selrow == firstrow) - { - firstrow--; - lastrow--; - wins_scrollwin_up (&kwin, LINESPERKEY); - } - } - break; - case KEY_MOVE_DOWN: - if (selrow < NBKEYS - 1) - { - selrow++; - selelm = 0; - if (selrow == lastrow) - { - firstrow++; - lastrow++; - wins_scrollwin_down (&kwin, LINESPERKEY); - } - } - break; - case KEY_MOVE_LEFT: - if (selelm > 0) - selelm--; - break; - case KEY_MOVE_RIGHT: - if (selelm < nbrowelm - 1) - selelm++; - break; - case KEY_GENERIC_HELP: - keys_popup_info (selrow); - break; - case KEY_ADD_ITEM: + for (;;) { + int ch; + + ch = keys_getch(win[STA].p, NULL); + switch (ch) { + case KEY_MOVE_UP: + if (selrow > 0) { + selrow--; + selelm = 0; + if (selrow == firstrow) { + firstrow--; + lastrow--; + wins_scrollwin_up(&kwin, LINESPERKEY); + } + } + break; + case KEY_MOVE_DOWN: + if (selrow < NBKEYS - 1) { + selrow++; + selelm = 0; + if (selrow == lastrow) { + firstrow++; + lastrow++; + wins_scrollwin_down(&kwin, LINESPERKEY); + } + } + break; + case KEY_MOVE_LEFT: + if (selelm > 0) + selelm--; + break; + case KEY_MOVE_RIGHT: + if (selelm < nbrowelm - 1) + selelm++; + break; + case KEY_GENERIC_HELP: + keys_popup_info(selrow); + break; + case KEY_ADD_ITEM: #define WINROW 10 #define WINCOL 50 - do - { - used = 0; - grabwin = popup (WINROW, WINCOL, (row - WINROW) / 2, - (col - WINCOL) / 2, - _("Press the key you want to assign to:"), - keys_get_label (selrow), 0); - keyval = wgetch (grabwin); - - /* First check if this key would be recognized by calcurse. */ - if (keys_str2int (keys_int2str (keyval)) == -1) - { - not_recognized = 1; - WARN_MSG (_("This key is not yet recognized by calcurse, " - "please choose another one.")); - werase (kwin.pad.p); - nbrowelm = print_keys_bindings (kwin.pad.p, selrow, selelm, - LINESPERKEY); - wins_scrollwin_display (&kwin); - continue; - } - else - not_recognized = 0; - - used = keys_assign_binding (keyval, selrow); - if (used) - { - enum key action; - - action = keys_get_action (keyval); - WARN_MSG (_("This key is already in use for %s, " - "please choose another one."), - keys_get_label (action)); - werase (kwin.pad.p); - nbrowelm = print_keys_bindings (kwin.pad.p, selrow, selelm, - LINESPERKEY); - wins_scrollwin_display (&kwin); - } - delwin (grabwin); - } - while (used || not_recognized); - nbrowelm++; - if (selelm < nbrowelm - 1) - selelm++; + do { + used = 0; + grabwin = popup(WINROW, WINCOL, (row - WINROW) / 2, + (col - WINCOL) / 2, + _("Press the key you want to assign to:"), + keys_get_label(selrow), 0); + keyval = wgetch(grabwin); + + /* First check if this key would be recognized by calcurse. */ + if (keys_str2int(keys_int2str(keyval)) == -1) { + not_recognized = 1; + WARN_MSG(_("This key is not yet recognized by calcurse, " + "please choose another one.")); + werase(kwin.pad.p); + nbrowelm = print_keys_bindings(kwin.pad.p, selrow, selelm, + LINESPERKEY); + wins_scrollwin_display(&kwin); + continue; + } else + not_recognized = 0; + + used = keys_assign_binding(keyval, selrow); + if (used) { + enum key action; + + action = keys_get_action(keyval); + WARN_MSG(_("This key is already in use for %s, " + "please choose another one."), keys_get_label(action)); + werase(kwin.pad.p); + nbrowelm = print_keys_bindings(kwin.pad.p, selrow, selelm, + LINESPERKEY); + wins_scrollwin_display(&kwin); + } + delwin(grabwin); + } + while (used || not_recognized); + nbrowelm++; + if (selelm < nbrowelm - 1) + selelm++; #undef WINROW #undef WINCOL - break; - case KEY_DEL_ITEM: - keystr = keys_action_nkey (selrow, selelm); - keyval = keys_str2int (keystr); - keys_remove_binding (keyval, selrow); - nbrowelm--; - if (selelm > 0 && selelm <= nbrowelm) - selelm--; - break; - case KEY_GENERIC_QUIT: - if (keys_check_missing_bindings () != 0) - { - WARN_MSG (_("Some actions do not have any associated " - "key bindings!")); - } - wins_scrollwin_delete (&kwin); - return; - } - custom_keys_config_bar (); - werase (kwin.pad.p); - nbrowelm = print_keys_bindings (kwin.pad.p, selrow, selelm, LINESPERKEY); - wins_scrollwin_display (&kwin); + break; + case KEY_DEL_ITEM: + keystr = keys_action_nkey(selrow, selelm); + keyval = keys_str2int(keystr); + keys_remove_binding(keyval, selrow); + nbrowelm--; + if (selelm > 0 && selelm <= nbrowelm) + selelm--; + break; + case KEY_GENERIC_QUIT: + if (keys_check_missing_bindings() != 0) { + WARN_MSG(_("Some actions do not have any associated " "key bindings!")); + } + wins_scrollwin_delete(&kwin); + return; + } + custom_keys_config_bar(); + werase(kwin.pad.p); + nbrowelm = print_keys_bindings(kwin.pad.p, selrow, selelm, LINESPERKEY); + wins_scrollwin_display(&kwin); + } +} + +void custom_config_main(void) +{ + const char *no_color_support = + _("Sorry, colors are not supported by your terminal\n" + "(Press [ENTER] to continue)"); + int ch; + int old_layout; + + custom_config_bar(); + while ((ch = wgetch(win[STA].p)) != 'q') { + switch (ch) { + case 'C': + case 'c': + if (has_colors()) + custom_color_config(); + else { + colorize = 0; + wins_erase_status_bar(); + mvwprintw(win[STA].p, 0, 0, _(no_color_support)); + wgetch(win[STA].p); + } + break; + case 'L': + case 'l': + old_layout = wins_layout(); + custom_layout_config(); + if (wins_layout() != old_layout) + wins_reset(); + break; + case 'G': + case 'g': + custom_general_config(); + break; + case 'N': + case 'n': + notify_config_bar(); + break; + case 'K': + case 'k': + custom_keys_config(); + break; + case 's': + case 'S': + custom_sidebar_config(); + break; + default: + continue; } + wins_update(FLAG_ALL); + wins_erase_status_bar(); + custom_config_bar(); + } } @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -43,26 +43,24 @@ #include "calcurse.h" struct day_saved_item { - char start[BUFSIZ]; - char end[BUFSIZ]; - char state; - char type; + 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 llist_t day_items; +static struct day_saved_item day_saved_item; -static void -day_free (struct day_item *day) +static void day_free(struct day_item *day) { - mem_free (day); + mem_free(day); } -static void -day_init_list (void) +static void day_init_list(void) { - LLIST_INIT (&day_items); + LLIST_INIT(&day_items); } /* @@ -70,20 +68,19 @@ day_init_list (void) * Must not free associated message and note, because their are not dynamically * allocated (only pointers to real objects are stored in this structure). */ -void -day_free_list (void) +void day_free_list(void) { - LLIST_FREE_INNER (&day_items, day_free); - LLIST_FREE (&day_items); + LLIST_FREE_INNER(&day_items, day_free); + 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) +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 = mem_malloc(sizeof(struct day_item)); day->mesg = mesg; day->note = note; day->type = type; @@ -92,35 +89,32 @@ day_add_event (int type, char *mesg, char *note, long nday, int id) day->start = nday; day->evnt_id = id; - LLIST_ADD (&day_items, day); + LLIST_ADD(&day_items, day); return day; } -static int -day_cmp_start (struct day_item *a, struct day_item *b) +static int day_cmp_start(struct day_item *a, struct day_item *b) { - if (a->type <= EVNT) - { - if (b->type <= EVNT) - return 0; - else - return -1; - } - else if (b->type <= EVNT) + if (a->type <= EVNT) { + if (b->type <= EVNT) + return 0; + else + return -1; + } else if (b->type <= EVNT) return 1; else - return (a->start < b->start ? -1 : (a->start == b->start ? 0 : 1)); + 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) +static struct day_item *day_add_apoint(int type, char *mesg, char *note, + long start, long dur, char state, + int real_pos) { struct day_item *day; - day = mem_malloc (sizeof (struct day_item)); + day = mem_malloc(sizeof(struct day_item)); day->mesg = mesg; day->note = note; day->start = start; @@ -130,7 +124,7 @@ day_add_apoint (int type, char *mesg, char *note, long start, long dur, day->type = type; day->evnt_id = 0; - LLIST_ADD_SORTED (&day_items, day, day_cmp_start); + LLIST_ADD_SORTED(&day_items, day, day_cmp_start); return day; } @@ -142,18 +136,16 @@ day_add_apoint (int type, char *mesg, char *note, long start, long dur, * 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) { llist_item_t *i; int e_nb = 0; - LLIST_FIND_FOREACH (&eventlist, date, event_inday, i) - { - struct event *ev = LLIST_TS_GET_DATA (i); - (void)day_add_event (EVNT, ev->mesg, ev->note, ev->day, ev->id); - e_nb++; - } + 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); + e_nb++; + } return e_nb; } @@ -165,19 +157,16 @@ 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) { llist_item_t *i; int e_nb = 0; - LLIST_FIND_FOREACH (&recur_elist, date, recur_event_inday, i) - { - struct recur_event *rev = LLIST_TS_GET_DATA (i); - (void)day_add_event (RECUR_EVNT, rev->mesg, rev->note, rev->day, - rev->id); - e_nb++; - } + 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); + e_nb++; + } return e_nb; } @@ -189,21 +178,23 @@ 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) { llist_item_t *i; int a_nb = 0; - LLIST_TS_LOCK (&alist_p); - LLIST_TS_FIND_FOREACH (&alist_p, date, apoint_inday, i) - { - struct apoint *apt = LLIST_TS_GET_DATA (i); - (void)day_add_apoint (APPT, apt->mesg, apt->note, apt->start, apt->dur, - apt->state, 0); - a_nb++; - } - LLIST_TS_UNLOCK (&alist_p); + LLIST_TS_LOCK(&alist_p); + LLIST_TS_FIND_FOREACH(&alist_p, date, apoint_inday, i) { + struct apoint *apt = LLIST_TS_GET_DATA(i); + + if (apt->start >= date + DAYINSEC) + break; + + day_add_apoint(APPT, apt->mesg, apt->note, apt->start, apt->dur, + apt->state, 0); + a_nb++; + } + LLIST_TS_UNLOCK(&alist_p); return a_nb; } @@ -215,22 +206,22 @@ 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) { llist_item_t *i; int a_nb = 0; - LLIST_TS_LOCK (&recur_alist_p); - LLIST_TS_FIND_FOREACH (&recur_alist_p, date, recur_apoint_inday, i) - { - struct recur_apoint *rapt = LLIST_TS_GET_DATA (i); - int real_start = recur_apoint_inday (rapt, date); - (void)day_add_apoint (RECUR_APPT, rapt->mesg, rapt->note, real_start, - rapt->dur, rapt->state, a_nb); + LLIST_TS_LOCK(&recur_alist_p); + LLIST_TS_FIND_FOREACH(&recur_alist_p, date, recur_apoint_inday, i) { + struct recur_apoint *rapt = LLIST_TS_GET_DATA(i); + 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); a_nb++; } - LLIST_TS_UNLOCK (&recur_alist_p); + } + LLIST_TS_UNLOCK(&recur_alist_p); return a_nb; } @@ -244,19 +235,19 @@ day_store_recur_apoints (long date) * 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) +day_store_items(long date, unsigned *pnb_events, unsigned *pnb_apoints) { 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); + 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); + 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)); @@ -271,9 +262,9 @@ day_store_items (long date, unsigned *pnb_events, unsigned *pnb_apoints) * those items in a pad. If selected day is null, then store items for current * day. This is useful to speed up the appointment panel update. */ -struct day_items_nb * -day_process_storage (struct date *slctd_date, unsigned day_changed, - struct day_items_nb *inday) +struct day_items_nb *day_process_storage(struct date *slctd_date, + unsigned day_changed, + struct day_items_nb *inday) { long date; struct date day; @@ -281,21 +272,21 @@ day_process_storage (struct date *slctd_date, unsigned day_changed, if (slctd_date) day = *slctd_date; else - calendar_store_current_date (&day); + calendar_store_current_date(&day); - date = date2sec (day, 0, 0); + date = date2sec(day, 0, 0); /* Inits */ if (apad.length != 0) - delwin (apad.ptrwin); + delwin(apad.ptrwin); /* Store the events and appointments (recursive and normal items). */ - apad.length = day_store_items (date, &inday->nb_events, &inday->nb_apoints); + apad.length = day_store_items(date, &inday->nb_events, &inday->nb_apoints); /* Create the new pad with its new length. */ if (day_changed) apad.first_onscreen = 0; - apad.ptrwin = newpad (apad.length, apad.width); + apad.ptrwin = newpad(apad.length, apad.width); return inday; } @@ -304,8 +295,7 @@ day_process_storage (struct date *slctd_date, unsigned day_changed, * 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) +static void day_item_s2apoint_s(struct apoint *a, struct day_item *p) { a->state = p->state; a->start = p->start; @@ -317,61 +307,65 @@ day_item_s2apoint_s (struct apoint *a, struct day_item *p) * 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(int incolor, struct apoint *i, int type, long date, + int y, int x) { WINDOW *win; char a_st[100], a_end[100]; - int recur = 0; win = apad.ptrwin; - apoint_sec2str (i, type, date, a_st, a_end); - if (type == RECUR_EVNT || type == RECUR_APPT) - recur = 1; + apoint_sec2str(i, date, a_st, a_end); if (incolor == 0) - custom_apply_attr (win, ATTR_HIGHEST); - if (recur) + custom_apply_attr(win, ATTR_HIGHEST); + if (type == RECUR_EVNT || type == RECUR_APPT) if (i->state & APOINT_NOTIFY) - mvwprintw (win, y, x, " *!%s -> %s", a_st, a_end); + mvwprintw(win, y, x, " *!%s -> %s", a_st, a_end); else - mvwprintw (win, y, x, " * %s -> %s", a_st, a_end); + mvwprintw(win, y, x, " * %s -> %s", a_st, a_end); else if (i->state & APOINT_NOTIFY) - mvwprintw (win, y, x, " -!%s -> %s", a_st, a_end); + mvwprintw(win, y, x, " -!%s -> %s", a_st, a_end); else - mvwprintw (win, y, x, " - %s -> %s", a_st, a_end); + mvwprintw(win, y, x, " - %s -> %s", a_st, a_end); if (incolor == 0) - custom_remove_attr (win, ATTR_HIGHEST); + custom_remove_attr(win, ATTR_HIGHEST); } /* * Print an item description in the corresponding panel window. */ static void -display_item (int incolor, char *msg, int recur, int note, int len, int y, - int x) +display_item(int incolor, char *msg, int recur, int note, int width, int y, + int x) { WINDOW *win; int ch_recur, ch_note; - char buf[len]; + char buf[width * UTF8_MAXLEN]; + int i; - if (len <= 0) + if (width <= 0) return; win = apad.ptrwin; ch_recur = (recur) ? '*' : ' '; ch_note = (note) ? '>' : ' '; if (incolor == 0) - custom_apply_attr (win, ATTR_HIGHEST); - if (strlen (msg) < len) - mvwprintw (win, y, x, " %c%c%s", ch_recur, ch_note, msg); - else - { - (void)strncpy (buf, msg, len - 1); - buf[len - 1] = '\0'; - mvwprintw (win, y, x, " %c%c%s...", ch_recur, ch_note, buf); + custom_apply_attr(win, ATTR_HIGHEST); + if (utf8_strwidth(msg) < width) + mvwprintw(win, y, x, " %c%c%s", ch_recur, ch_note, msg); + else { + for (i = 0; msg[i] && width > 0; i++) { + if (!UTF8_ISCONT(msg[i])) + width -= utf8_width(&msg[i]); + buf[i] = msg[i]; } + if (i) + buf[i - 1] = 0; + else + buf[0] = 0; + mvwprintw(win, y, x, " %c%c%s...", ch_recur, ch_note, buf); + } if (incolor == 0) - custom_remove_attr (win, ATTR_HIGHEST); + custom_remove_attr(win, ATTR_HIGHEST); } /* @@ -381,8 +375,7 @@ display_item (int incolor, char *msg, int recur, int note, int len, int y, * structure (pointed by day_saved_item), to be later displayed in a * popup window if requested. */ -void -day_write_pad (long date, int width, int length, int incolor) +void day_write_pad(long date, int width, int length, int incolor) { llist_item_t *i; struct apoint a; @@ -392,67 +385,57 @@ day_write_pad (long date, int width, int length, int incolor) line = item_number = 0; - 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); - line++; - draw_line = 1; - } - else - { - /* Draw a line between events and appointments. */ - if (line > 0 && draw_line) - { - wmove (apad.ptrwin, line, 0); - whline (apad.ptrwin, 0, width); - draw_line = 0; - } - /* 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, day->type, 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); - line += 3; - } + 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); + line++; + draw_line = 1; + } else { + /* Draw a line between events and appointments. */ + if (line > 0 && draw_line) { + wmove(apad.ptrwin, line, 0); + whline(apad.ptrwin, 0, width); + draw_line = 0; + } + /* 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); + line += 3; } + } } /* Display an item inside a popup window. */ -void -day_popup_item (void) +void day_popup_item(void) { if (day_saved_item.type == EVNT || day_saved_item.type == RECUR_EVNT) - item_in_popup (NULL, NULL, day_saved_item.mesg, _("Event :")); + 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 :")); + item_in_popup(day_saved_item.start, day_saved_item.end, + day_saved_item.mesg, _("Appointment :")); else - EXIT (_("unknown item type")); + EXIT(_("unknown item type")); /* NOTREACHED */ } @@ -460,38 +443,34 @@ day_popup_item (void) * Need to know if there is an item for the current selected day inside * calendar. This is used to put the correct colors inside calendar panel. */ -int -day_check_if_item (struct date day) +int day_check_if_item(struct date day) { - const long date = date2sec (day, 0, 0); + const long date = date2sec(day, 0, 0); - if (LLIST_FIND_FIRST (&recur_elist, date, recur_event_inday)) - return (1); + if (LLIST_FIND_FIRST(&recur_elist, date, recur_event_inday)) + return 1; - LLIST_TS_LOCK (&recur_alist_p); - if (LLIST_TS_FIND_FIRST (&recur_alist_p, date, recur_apoint_inday)) - { - LLIST_TS_UNLOCK (&recur_alist_p); - return (1); - } - LLIST_TS_UNLOCK (&recur_alist_p); + LLIST_TS_LOCK(&recur_alist_p); + if (LLIST_TS_FIND_FIRST(&recur_alist_p, 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)) - return (1); + if (LLIST_FIND_FIRST(&eventlist, date, event_inday)) + return 1; - LLIST_TS_LOCK (&alist_p); - if (LLIST_TS_FIND_FIRST (&alist_p, date, apoint_inday)) - { - LLIST_TS_UNLOCK (&alist_p); - return (1); - } - LLIST_TS_UNLOCK (&alist_p); + LLIST_TS_LOCK(&alist_p); + if (LLIST_TS_FIND_FIRST(&alist_p, date, apoint_inday)) { + LLIST_TS_UNLOCK(&alist_p); + return 1; + } + LLIST_TS_UNLOCK(&alist_p); - return (0); + return 0; } -static unsigned -fill_slices (int *slices, int slicesno, int first, int last) +static unsigned fill_slices(int *slices, int slicesno, int first, int last) { int i; @@ -499,7 +478,7 @@ fill_slices (int *slices, int slicesno, int first, int last) return 0; if (last >= slicesno) - last = slicesno - 1; /* Appointment spanning more than one day. */ + last = slicesno - 1; /* Appointment spanning more than one day. */ for (i = first; i <= last; i++) slices[i] = 1; @@ -512,353 +491,375 @@ fill_slices (int *slices, int slicesno, int first, int last) * appointment in the corresponding time slice, 0 otherwise. * A 24 hours day is divided into 'slicesno' number of time slices. */ -unsigned -day_chk_busy_slices (struct date day, int slicesno, int *slices) +unsigned day_chk_busy_slices(struct date day, int slicesno, int *slices) { llist_item_t *i; int slicelen; - const long date = date2sec (day, 0, 0); + const long date = date2sec(day, 0, 0); slicelen = DAYINSEC / slicesno; #define SLICENUM(tsec) ((tsec) / slicelen % slicesno) - LLIST_TS_LOCK (&recur_alist_p); - LLIST_TS_FIND_FOREACH (&recur_alist_p, 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); - - if (!fill_slices (slices, slicesno, SLICENUM (start), SLICENUM (end))) - { - LLIST_TS_UNLOCK (&recur_alist_p); - return 0; - } + LLIST_TS_LOCK(&recur_alist_p); + LLIST_TS_FIND_FOREACH(&recur_alist_p, 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); + + if (!fill_slices(slices, slicesno, SLICENUM(start), SLICENUM(end))) { + LLIST_TS_UNLOCK(&recur_alist_p); + return 0; } - LLIST_TS_UNLOCK (&recur_alist_p); - - LLIST_TS_LOCK (&alist_p); - LLIST_TS_FIND_FOREACH (&alist_p, 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); - - if (!fill_slices (slices, slicesno, SLICENUM (start), SLICENUM (end))) - { - LLIST_TS_UNLOCK (&alist_p); - return 0; - } + } + LLIST_TS_UNLOCK(&recur_alist_p); + + LLIST_TS_LOCK(&alist_p); + LLIST_TS_FIND_FOREACH(&alist_p, 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); + + if (apt->start >= date + DAYINSEC) + break; + + if (!fill_slices(slices, slicesno, SLICENUM(start), SLICENUM(end))) { + LLIST_TS_UNLOCK(&alist_p); + return 0; } - LLIST_TS_UNLOCK (&alist_p); + } + LLIST_TS_UNLOCK(&alist_p); #undef SLICENUM return 1; } /* Request the user to enter a new time. */ -static char * -day_edit_time (long time) +static int day_edit_time(int time, unsigned *new_hour, unsigned *new_minute) { - char *timestr; - char *msg_time = _("Enter the new time ([hh:mm] or [h:mm]) : "); - char *enter_str = _("Press [Enter] to continue"); - char *fmt_msg = _("You entered an invalid time, should be [h:mm] or [hh:mm]"); - - while (1) - { - status_mesg (msg_time, ""); - timestr = date_sec2date_str (time, "%H:%M"); - updatestring (win[STA].p, ×tr, 0, 1); - if (check_time (timestr) != 1 || strlen (timestr) == 0) - { - status_mesg (fmt_msg, enter_str); - (void)wgetch (win[STA].p); - } - else - return (timestr); - } + 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, ×tr, 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; + } } -static void -update_start_time (long *start, long *dur) +/* 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, ×tr, 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; - char *timestr; - char *msg_wrong_time = _("Invalid time: start time must be before end time!"); - char *msg_enter = _("Press [Enter] to continue"); - - do - { - timestr = day_edit_time (*start); - (void)sscanf (timestr, "%u:%u", &hr, &mn); - mem_free (timestr); - 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); - (void)wgetch (win[STA].p); - valid_date = 0; - } + 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) +static void update_duration(long *start, long *dur) { - long newtime; - unsigned hr, mn; - char *timestr; + unsigned newdur; - timestr = day_edit_time (*start + *dur); - (void)sscanf (timestr, "%u:%u", &hr, &mn); - mem_free (timestr); - newtime = update_time_in_date (*start, hr, mn); - *dur = (newtime > *start) ? newtime - *start : DAYINSEC + newtime - *start; + day_edit_duration(*start, *dur, &newdur); + *dur = newdur; } -static void -update_desc (char **desc) +static void update_desc(char **desc) { - status_mesg (_("Enter the new item description:"), ""); - updatestring (win[STA].p, desc, 0, 1); + status_mesg(_("Enter the new item description:"), ""); + updatestring(win[STA].p, desc, 0, 1); } -static void -update_rept (struct rpt **rpt, const long start, struct conf *conf) +static void update_rept(struct rpt **rpt, const long start) { - const int SINGLECHAR = 2; - int ch, cancel, newfreq, date_entered; + int newtype, newfreq, date_entered; long newuntil; char outstr[BUFSIZ]; - char *typstr, *freqstr, *timstr; - char *msg_rpt_type = _("Enter the new repetition type: (D)aily, (W)eekly, " - "(M)onthly, (Y)early"); - char *msg_rpt_ans = _("[D/W/M/Y] "); - char *msg_wrong_freq = _("The frequence you entered is not valid."); - char *msg_wrong_time = _("Invalid time: start time must be before end time!"); - char *msg_wrong_date = _("The entered date is not valid."); - char *msg_fmts = - "Possible formats are [%s] or '0' for an endless repetetition"; - char *msg_enter = _("Press [Enter] to continue"); - - do - { - status_mesg (msg_rpt_type, msg_rpt_ans); - typstr = mem_calloc (SINGLECHAR, sizeof (char)); - (void)snprintf (typstr, SINGLECHAR, "%c", recur_def2char ((*rpt)->type)); - cancel = updatestring (win[STA].p, &typstr, 0, 1); - if (cancel) - { - mem_free (typstr); - return; - } - else - { - ch = toupper (*typstr); - mem_free (typstr); - } - } - while ((ch != 'D') && (ch != 'W') && (ch != 'M') && (ch != 'Y')); - - do - { - status_mesg (_("Enter the new repetition frequence:"), ""); - freqstr = mem_malloc (BUFSIZ); - (void)snprintf (freqstr, BUFSIZ, "%d", (*rpt)->freq); - cancel = updatestring (win[STA].p, &freqstr, 0, 1); - if (cancel) - { - mem_free (freqstr); - return; - } - else - { - newfreq = atoi (freqstr); - mem_free (freqstr); - if (newfreq == 0) - { - status_mesg (msg_wrong_freq, msg_enter); - (void)wgetch (win[STA].p); - } - } + 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 repetetition"); + 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 - { - (void)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)); - cancel = updatestring (win[STA].p, &timstr, 0, 1); - if (cancel) - { - mem_free (timstr); - return; - } - if (strcmp (timstr, "0") == 0) - { - newuntil = 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; + lt = localtime(&t); + 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 - { - 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; - lt = localtime (&t); - 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); - (void)wgetch (win[STA].p); - date_entered = 0; - } - else - date_entered = 1; - } - else - { - (void)snprintf (outstr, BUFSIZ, msg_fmts, - DATEFMT_DESC (conf->input_datefmt)); - status_mesg (msg_wrong_date, _(outstr)); - (void)wgetch (win[STA].p); - date_entered = 0; - } - } + } 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 (ch); + mem_free(timstr); + (*rpt)->type = recur_char2def(newtype); (*rpt)->freq = newfreq; (*rpt)->until = newuntil; } /* Edit an already existing item. */ -void -day_edit_item (struct conf *conf) +void day_edit_item(void) { -#define STRT '1' -#define END '2' -#define DESC '3' -#define REPT '4' - struct day_item *p; struct recur_event *re; struct event *e; struct recur_apoint *ra; struct apoint *a; long date; - int item_num, ch; + int item_num; int need_check_notify = 0; - item_num = apoint_hilt (); - p = day_get_item (item_num); - date = calendar_get_slctd_day_sec (); - - ch = -1; - switch (p->type) - { - case RECUR_EVNT: - re = recur_get_event (date, day_item_nb (date, item_num, RECUR_EVNT)); - status_mesg (_("Edit: (1)Description or (2)Repetition?"), "[1/2] "); - while (ch != '1' && ch != '2' && ch != KEY_GENERIC_CANCEL) - ch = wgetch (win[STA].p); - switch (ch) - { - case '1': - update_desc (&re->mesg); - break; - case '2': - update_rept (&re->rpt, re->day, conf); - break; - default: - return; - } + 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 EVNT: - e = event_get (date, day_item_nb (date, item_num, EVNT)); - update_desc (&e->mesg); + case 2: + update_rept(&re->rpt, re->day); break; - case RECUR_APPT: - ra = recur_get_apoint (date, day_item_nb (date, item_num, RECUR_APPT)); - status_mesg (_("Edit: (1)Start time, (2)End time, " - "(3)Description or (4)Repetition?"), "[1/2/3/4] "); - while (ch != STRT && ch != END && ch != DESC && - ch != REPT && ch != KEY_GENERIC_CANCEL) - ch = wgetch (win[STA].p); - switch (ch) - { - case STRT: - need_check_notify = 1; - update_start_time (&ra->start, &ra->dur); - break; - case END: - update_duration (&ra->start, &ra->dur); - break; - case DESC: - if (notify_bar ()) - need_check_notify = notify_same_recur_item (ra); - update_desc (&ra->mesg); - break; - case REPT: - need_check_notify = 1; - update_rept (&ra->rpt, ra->start, conf); - break; - case KEY_GENERIC_CANCEL: - return; - } + 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 APPT: - a = apoint_get (date, day_item_nb (date, item_num, APPT)); - status_mesg (_("Edit: (1)Start time, (2)End time " - "or (3)Description?"), "[1/2/3] "); - while (ch != STRT && ch != END && ch != DESC && ch != KEY_GENERIC_CANCEL) - ch = wgetch (win[STA].p); - switch (ch) - { - case STRT: - need_check_notify = 1; - update_start_time (&a->start, &a->dur); - break; - case END: - update_duration (&a->start, &a->dur); - break; - case DESC: - if (notify_bar ()) - need_check_notify = notify_same_item (a->start); - update_desc (&a->mesg); - break; - case KEY_GENERIC_CANCEL: - return; - } + 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); + notify_check_next_app(1); } /* @@ -867,157 +868,142 @@ day_edit_item (struct conf *conf) * 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) +int day_erase_item(long date, int item_number, enum eraseflg flag) { struct day_item *p; - char *erase_warning = + + const char *erase_warning = _("This item is recurrent. " "Delete (a)ll occurences or just this (o)ne ?"); - char *note_warning = + 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 ?"); - char *note_choice = _("[i/n] "); - char *erase_choice = _("[a/o] "); - int ch, ans; + const char *note_choices = _("[in]"); + const int nb_note_choices = 2; + int ans; unsigned delete_whole; - ch = -1; - p = day_get_item (item_number); - if (flag == ERASE_DONT_FORCE) - { - ans = 0; - if (p->note == NULL) - ans = 'i'; - while (ans != 'i' && ans != 'n') - { - status_mesg (note_warning, note_choice); - ans = wgetch (win[STA].p); - } - if (ans == 'i') - flag = ERASE_FORCE; - else - flag = ERASE_FORCE_ONLY_NOTE; - } - if (p->type == EVNT) - { - event_delete_bynum (date, day_item_nb (date, item_number, EVNT), flag); + 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; } - else if (p->type == APPT) - { - apoint_delete_bynum (date, day_item_nb (date, item_number, APPT), flag); + } + 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; } - else - { - if (flag == ERASE_FORCE_ONLY_NOTE) - ch = 'a'; - while ((ch != 'a') && (ch != 'o') && (ch != KEY_GENERIC_CANCEL)) - { - status_mesg (erase_warning, erase_choice); - ch = wgetch (win[STA].p); - } - if (ch == 'a') - { - delete_whole = 1; - } - else if (ch == 'o') - { - delete_whole = 0; - } - else - { - 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 (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); + return p->type; } /* Cut an item so it can be pasted somewhere else later. */ -int -day_cut_item (long date, int item_number) +int day_cut_item(long date, int item_number) { const int DELETE_WHOLE = 1; struct day_item *p; - p = day_get_item (item_number); - switch (p->type) - { - case EVNT: - event_delete_bynum (date, day_item_nb (date, item_number, EVNT), - ERASE_CUT); - break; - case RECUR_EVNT: - recur_event_erase (date, day_item_nb (date, item_number, RECUR_EVNT), - DELETE_WHOLE, ERASE_CUT); - break; - case APPT: - apoint_delete_bynum (date, day_item_nb (date, item_number, APPT), - ERASE_CUT); - break; - case RECUR_APPT: - recur_apoint_erase (date, p->appt_pos, DELETE_WHOLE, ERASE_CUT); - break; - default: - EXIT (_("unknwon type")); - /* NOTREACHED */ - } + p = day_get_item(item_number); + switch (p->type) { + case EVNT: + event_delete_bynum(date, day_item_nb(date, item_number, EVNT), ERASE_CUT); + break; + case RECUR_EVNT: + recur_event_erase(date, day_item_nb(date, item_number, RECUR_EVNT), + DELETE_WHOLE, ERASE_CUT); + break; + case APPT: + apoint_delete_bynum(date, day_item_nb(date, item_number, APPT), ERASE_CUT); + break; + case RECUR_APPT: + recur_apoint_erase(date, p->appt_pos, DELETE_WHOLE, ERASE_CUT); + break; + default: + EXIT(_("unknwon type")); + /* NOTREACHED */ + } return p->type; } /* Paste a previously cut item. */ -int -day_paste_item (long date, int cut_item_type) +int day_paste_item(long date, int cut_item_type) { int pasted_item_type; pasted_item_type = cut_item_type; - switch (cut_item_type) - { - case 0: - return 0; - case EVNT: - event_paste_item (); - break; - case RECUR_EVNT: - recur_event_paste_item (); - break; - case APPT: - apoint_paste_item (); - break; - case RECUR_APPT: - recur_apoint_paste_item (); - break; - default: - EXIT (_("unknwon type")); - /* NOTREACHED */ - } + switch (cut_item_type) { + case 0: + return 0; + case EVNT: + event_paste_item(); + break; + case RECUR_EVNT: + recur_event_paste_item(); + break; + case APPT: + apoint_paste_item(); + break; + case RECUR_APPT: + recur_apoint_paste_item(); + break; + default: + EXIT(_("unknwon type")); + /* NOTREACHED */ + } return pasted_item_type; } /* Returns a structure containing the selected item. */ -struct day_item * -day_get_item (int item_number) +struct day_item *day_get_item(int item_number) { - return LLIST_GET_DATA (LLIST_NTH (&day_items, item_number - 1)); + 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 day_item_nb(long date, int day_num, int type) { int i, nb_item[MAX_TYPES]; llist_item_t *j; @@ -1025,78 +1011,108 @@ day_item_nb (long date, int day_num, int type) 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); - } + 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]); + return nb_item[type - 1]; } /* Attach a note to an appointment or event. */ -void -day_edit_note (char *editor) +void day_edit_note(const char *editor) { struct day_item *p; struct recur_apoint *ra; struct apoint *a; struct recur_event *re; struct event *e; - char fullname[BUFSIZ]; - char *filename; long date; int item_num; - item_num = apoint_hilt (); - p = day_get_item (item_num); - if (p->note == NULL) - { - if ((filename = new_tempfile (path_notes, NOTESIZ)) == NULL) - return; - else - p->note = filename; - } - (void)snprintf (fullname, BUFSIZ, "%s%s", path_notes, p->note); - wins_launch_external (fullname, editor); + item_num = apoint_hilt(); + p = day_get_item(item_num); + edit_note(&p->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; + break; + case EVNT: + e = event_get(date, day_item_nb(date, item_num, EVNT)); + e->note = p->note; + break; + case RECUR_APPT: + ra = recur_get_apoint(date, day_item_nb(date, item_num, RECUR_APPT)); + ra->note = p->note; + break; + case APPT: + a = apoint_get(date, day_item_nb(date, item_num, APPT)); + a->note = p->note; + break; + } +} + +/* View a note previously attached to an appointment or event */ +void day_view_note(const char *pager) +{ + struct day_item *p = day_get_item(apoint_hilt()); + view_note(p->note, pager); +} - if (io_file_is_empty (fullname) > 0) - erase_note (&p->note, ERASE_FORCE); +/* Pipe an appointment or event to an external program. */ +void day_pipe_item(void) +{ + 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; - date = calendar_get_slctd_day_sec (); - switch (p->type) - { + 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)); - re->note = p->note; + 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)); - e->note = p->note; + 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)); - ra->note = p->note; + 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)); - a->note = p->note; + a = apoint_get(date, day_item_nb(date, item_num, APPT)); + apoint_write(a, fpout); break; } -} - -/* View a note previously attached to an appointment or event */ -void -day_view_note (char *pager) -{ - struct day_item *p; - char fullname[BUFSIZ]; - p = day_get_item (apoint_hilt ()); - if (p->note == NULL) - return; - (void)snprintf (fullname, BUFSIZ, "%s%s", path_notes, p->note); - wins_launch_external (fullname, pager); + fclose(fpout); + child_wait(NULL, &pout, pid); + press_any_key(); + } + wins_unprepare_external(); } @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -49,7 +49,7 @@ #define DMON_LOG(...) do { \ if (dmon.log) \ - (void)io_fprintln (path_dmon_log, __VA_ARGS__); \ + io_fprintln (path_dmon_log, __VA_ARGS__); \ } while (0) #define DMON_ABRT(...) do { \ @@ -64,26 +64,22 @@ static unsigned data_loaded; -static void -dmon_sigs_hdlr (int sig) +static void dmon_sigs_hdlr(int sig) { if (data_loaded) - free_user_data (); + free_user_data(); - DMON_LOG (_("terminated at %s with signal %d\n"), nowstr (), sig); + DMON_LOG(_("terminated at %s with signal %d\n"), nowstr(), sig); - if (unlink (path_dpid) != 0) - { - DMON_LOG (_("Could not remove daemon lock file: %s\n"), - strerror (errno)); - exit (EXIT_FAILURE); - } + if (unlink(path_dpid) != 0) { + DMON_LOG(_("Could not remove daemon lock file: %s\n"), strerror(errno)); + exit(EXIT_FAILURE); + } - exit (EXIT_SUCCESS); + exit(EXIT_SUCCESS); } -static unsigned -daemonize (int status) +static unsigned daemonize(int status) { int fd; @@ -93,16 +89,15 @@ daemonize (int status) * First need to fork in order to become a child of the init process, * once the father exits. */ - switch (fork ()) - { - case -1: /* fork error */ - EXIT (_("Could not fork: %s\n"), strerror (errno)); - break; - case 0: /* child */ - break; - default: /* parent */ - exit (status); - } + switch (fork()) { + case -1: /* fork error */ + EXIT(_("Could not fork: %s\n"), strerror(errno)); + break; + case 0: /* child */ + break; + default: /* parent */ + exit(status); + } /* * Process independency. @@ -110,110 +105,99 @@ daemonize (int status) * Obtain a new process group and session in order to get detached from the * controlling terminal. */ - if (setsid () == -1) - { - DMON_LOG (_("Could not detach from the controlling terminal: %s\n"), - strerror (errno)); - return 0; - } + if (setsid() == -1) { + DMON_LOG(_("Could not detach from the controlling terminal: %s\n"), + strerror(errno)); + return 0; + } /* * Change working directory to root directory, * to prevent filesystem unmounts. */ - if (chdir ("/") == -1) - { - DMON_LOG (_("Could not change working directory: %s\n"), - strerror (errno)); - return 0; - } + if (chdir("/") == -1) { + DMON_LOG(_("Could not change working directory: %s\n"), strerror(errno)); + return 0; + } /* Redirect standard file descriptors to /dev/null. */ - if ((fd = open (_PATH_DEVNULL, O_RDWR, 0)) != -1) - { - (void)dup2 (fd, STDIN_FILENO); - (void)dup2 (fd, STDOUT_FILENO); - (void)dup2 (fd, STDERR_FILENO); - if (fd > 2) - (void)close (fd); - } + if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > 2) + close(fd); + } /* Write access for the owner only. */ - (void)umask (0022); + umask(0022); - if (!sigs_set_hdlr (SIGINT, dmon_sigs_hdlr) - || !sigs_set_hdlr (SIGTERM, dmon_sigs_hdlr) - || !sigs_set_hdlr (SIGALRM, dmon_sigs_hdlr) - || !sigs_set_hdlr (SIGQUIT, dmon_sigs_hdlr) - || !sigs_set_hdlr (SIGCHLD, SIG_IGN)) + if (!sigs_set_hdlr(SIGINT, dmon_sigs_hdlr) + || !sigs_set_hdlr(SIGTERM, dmon_sigs_hdlr) + || !sigs_set_hdlr(SIGALRM, dmon_sigs_hdlr) + || !sigs_set_hdlr(SIGQUIT, dmon_sigs_hdlr) + || !sigs_set_hdlr(SIGCHLD, SIG_IGN)) return 0; return 1; } -void -dmon_start (int parent_exit_status) +void dmon_start(int parent_exit_status) { - struct conf conf; - - if (!daemonize (parent_exit_status)) - DMON_ABRT (_("Cannot daemonize, aborting\n")); - - if (!io_dump_pid (path_dpid)) - DMON_ABRT (_("Could not set lock file\n")); - - if (!io_file_exist (path_conf)) - DMON_ABRT (_("Could not access \"%s\": %s\n"), - path_conf, strerror (errno)); - custom_load_conf (&conf, 0); - - if (!io_file_exist (path_apts)) - DMON_ABRT (_("Could not access \"%s\": %s\n"), - path_apts, strerror (errno)); - apoint_llist_init (); - recur_apoint_llist_init (); - event_llist_init (); - todo_init_list (); - io_load_app (); + if (!daemonize(parent_exit_status)) + DMON_ABRT(_("Cannot daemonize, aborting\n")); + + if (!io_dump_pid(path_dpid)) + DMON_ABRT(_("Could not set lock file\n")); + + if (!io_file_exist(path_conf)) + DMON_ABRT(_("Could not access \"%s\": %s\n"), path_conf, strerror(errno)); + config_load(); + + if (!io_file_exist(path_apts)) + DMON_ABRT(_("Could not access \"%s\": %s\n"), path_apts, strerror(errno)); + apoint_llist_init(); + recur_apoint_llist_init(); + event_llist_init(); + todo_init_list(); + io_load_app(); data_loaded = 1; - DMON_LOG (_("started at %s\n"), nowstr ()); - for (;;) - { - int left; - - if (!notify_get_next_bkgd ()) - DMON_ABRT (_("error loading next appointment\n")); - - left = notify_time_left (); - if (left > 0 && left < nbar.cntdwn && notify_needs_reminder ()) - { - DMON_LOG (_("launching notification at %s for: \"%s\"\n"), - nowstr (), notify_app_txt ()); - if (!notify_launch_cmd ()) - DMON_LOG (_("error while sending notification\n")); - } - - DMON_LOG (_("sleeping at %s for %d seconds\n"), nowstr (), - DMON_SLEEP_TIME); - psleep (DMON_SLEEP_TIME); - DMON_LOG (_("awakened at %s\n"), nowstr ()); + DMON_LOG(_("started at %s\n"), nowstr()); + for (;;) { + int left; + + if (!notify_get_next_bkgd()) + DMON_ABRT(_("error loading next appointment\n")); + + left = notify_time_left(); + if (left > 0 && left < nbar.cntdwn && notify_needs_reminder()) { + DMON_LOG(_("launching notification at %s for: \"%s\"\n"), + nowstr(), notify_app_txt()); + if (!notify_launch_cmd()) + DMON_LOG(_("error while sending notification\n")); } + + DMON_LOG(ngettext("sleeping at %s for %d second\n", + "sleeping at %s for %d seconds\n", + DMON_SLEEP_TIME), nowstr(), DMON_SLEEP_TIME); + psleep(DMON_SLEEP_TIME); + DMON_LOG(_("awakened at %s\n"), nowstr()); + } } /* * Check if calcurse is running in background, and if yes, send a SIGINT * signal to stop it. */ -void -dmon_stop (void) +void dmon_stop(void) { int dpid; - dpid = io_get_pid (path_dpid); + dpid = io_get_pid(path_dpid); if (!dpid) return; - if (kill ((pid_t)dpid, SIGINT) < 0 && errno != ESRCH) - EXIT (_("Could not stop calcurse daemon: %s\n"), strerror (errno)); + if (kill((pid_t) dpid, SIGINT) < 0 && errno != ESRCH) + EXIT(_("Could not stop calcurse daemon: %s\n"), strerror(errno)); } diff --git a/src/event.c b/src/event.c index c395ed8..f460ded 100644 --- a/src/event.c +++ b/src/event.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -41,181 +41,160 @@ #include "calcurse.h" -llist_t eventlist; -static struct event bkp_cut_event; +llist_t eventlist; +static struct event bkp_cut_event; -void -event_free_bkp (enum eraseflg flag) +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, flag); + 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) +static void event_free(struct event *ev) { - mem_free (ev->mesg); - erase_note (&ev->note, ERASE_FORCE_KEEP_NOTE); - mem_free (ev); + mem_free(ev->mesg); + erase_note(&ev->note); + mem_free(ev); } -static void -event_dup (struct event *in, struct event *bkp) +static void event_dup(struct event *in, struct event *bkp) { - EXIT_IF (!in || !bkp, _("null pointer")); + EXIT_IF(!in || !bkp, _("null pointer")); bkp->id = in->id; bkp->day = in->day; - bkp->mesg = mem_strdup (in->mesg); + bkp->mesg = mem_strdup(in->mesg); if (in->note) - bkp->note = mem_strdup (in->note); + bkp->note = mem_strdup(in->note); } -void -event_llist_init (void) +void event_llist_init(void) { - LLIST_INIT (&eventlist); + LLIST_INIT(&eventlist); } -void -event_llist_free (void) +void event_llist_free(void) { - LLIST_FREE_INNER (&eventlist, event_free); - LLIST_FREE (&eventlist); + LLIST_FREE_INNER(&eventlist, event_free); + LLIST_FREE(&eventlist); } -static int -event_cmp_day (struct event *a, struct event *b) +static int event_cmp_day(struct event *a, struct event *b) { - return (a->day < b->day ? -1 : (a->day == b->day ? 0 : 1)); + return a->day < b->day ? -1 : (a->day == b->day ? 0 : 1); } /* Create a new event */ -struct event * -event_new (char *mesg, char *note, long day, int id) +struct event *event_new(char *mesg, char *note, long day, int id) { struct event *ev; - ev = mem_malloc (sizeof (struct event)); - ev->mesg = mem_strdup (mesg); + ev = mem_malloc(sizeof(struct event)); + ev->mesg = mem_strdup(mesg); ev->day = day; ev->id = id; - ev->note = (note != NULL) ? mem_strdup (note) : NULL; + ev->note = (note != NULL) ? mem_strdup(note) : NULL; - LLIST_ADD_SORTED (&eventlist, ev, event_cmp_day); + LLIST_ADD_SORTED(&eventlist, ev, event_cmp_day); return ev; } /* 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) { - if (i->day <= start + DAYINSEC && i->day > start) - { - return (1); - } - return (0); + return (i->day < start + DAYINSEC && i->day >= start); } /* Write to file the event in user-friendly format */ -void -event_write (struct event *o, FILE *f) +void event_write(struct event *o, FILE * f) { struct tm *lt; time_t t; t = o->day; - lt = localtime (&t); - (void)fprintf (f, "%02u/%02u/%04u [%d] ", lt->tm_mon + 1, lt->tm_mday, - 1900 + lt->tm_year, o->id); + lt = localtime(&t); + fprintf(f, "%02u/%02u/%04u [%d] ", lt->tm_mon + 1, lt->tm_mday, + 1900 + lt->tm_year, o->id); if (o->note != NULL) - (void)fprintf (f, ">%s ", o->note); - (void)fprintf (f, "%s\n", o->mesg); + fprintf(f, ">%s ", o->note); + fprintf(f, "%s\n", o->mesg); } /* Load the events from file */ -struct event * -event_scan (FILE *f, struct tm start, int id, char *note) +struct event *event_scan(FILE * f, struct tm start, int id, char *note) { char buf[BUFSIZ], *nl; time_t tstart, t; - t = time (NULL); - (void)localtime (&t); + t = time(NULL); + localtime(&t); /* Read the event description */ - (void)fgets (buf, sizeof buf, f); - nl = strchr (buf, '\n'); - if (nl) - { - *nl = '\0'; - } - start.tm_hour = 12; + if (!fgets(buf, sizeof buf, f)) + return NULL; + + nl = strchr(buf, '\n'); + if (nl) { + *nl = '\0'; + } + start.tm_hour = 0; start.tm_min = 0; start.tm_sec = 0; start.tm_isdst = -1; start.tm_year -= 1900; start.tm_mon--; - tstart = mktime (&start); - EXIT_IF (tstart == -1, _("date error in the event\n")); + tstart = mktime(&start); + EXIT_IF(tstart == -1, _("date error in the event\n")); - return event_new (buf, note, tstart, id); + 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) +struct event *event_get(long day, int pos) { - llist_item_t *i = LLIST_FIND_NTH (&eventlist, pos, day, event_inday); + llist_item_t *i = LLIST_FIND_NTH(&eventlist, pos, day, event_inday); if (i) - return LLIST_TS_GET_DATA (i); + return LLIST_TS_GET_DATA(i); - EXIT (_("event not found")); + 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_bynum(long start, unsigned num, enum eraseflg flag) { - llist_item_t *i = LLIST_FIND_NTH (&eventlist, num, start, event_inday); + llist_item_t *i = LLIST_FIND_NTH(&eventlist, num, start, event_inday); 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, flag); - break; - case ERASE_CUT: - event_free_bkp (ERASE_FORCE); - event_dup (ev, &bkp_cut_event); - erase_note (&ev->note, ERASE_FORCE_KEEP_NOTE); - /* FALLTHROUGH */ - default: - LLIST_REMOVE (&eventlist, i); - mem_free (ev->mesg); - if (flag != ERASE_FORCE_KEEP_NOTE && flag != ERASE_CUT) - erase_note (&ev->note, flag); - mem_free (ev); - break; - } + 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; + } } -void -event_paste_item (void) +void event_paste_item(void) { - (void)event_new (bkp_cut_event.mesg, bkp_cut_event.note, - date2sec (*calendar_get_slctd_day (), 12, 0), - bkp_cut_event.id); - event_free_bkp (ERASE_FORCE_KEEP_NOTE); + event_new(bkp_cut_event.mesg, bkp_cut_event.note, + date2sec(*calendar_get_slctd_day(), 0, 0), bkp_cut_event.id); + event_free_bkp(); } diff --git a/src/getstring.c b/src/getstring.c new file mode 100644 index 0000000..cc2a949 --- /dev/null +++ b/src/getstring.c @@ -0,0 +1,280 @@ +/* + * 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 getstr_charinfo { + unsigned int offset, dpyoff; +}; + +struct getstr_status { + char *s; + struct getstr_charinfo *ci; + int pos, len; + int scrpos; +}; + +/* Print the string at the desired position. */ +static void getstr_print(WINDOW * win, int x, int y, struct getstr_status *st) +{ + char c = 0; + + /* print string */ + mvwaddnstr(win, y, x, &st->s[st->ci[st->scrpos].offset], -1); + wclrtoeol(win); + + /* print scrolling indicator */ + if (st->scrpos > 0 && st->ci[st->len].dpyoff - + st->ci[st->scrpos].dpyoff > col - 2) + c = '*'; + else if (st->scrpos > 0) + c = '<'; + else if (st->ci[st->len].dpyoff - st->ci[st->scrpos].dpyoff > col - 2) + c = '>'; + mvwprintw(win, y, col - 2, " %c", c); + + /* print cursor */ + wmove(win, y, st->ci[st->pos].dpyoff - st->ci[st->scrpos].dpyoff); + wchgat(win, 1, A_REVERSE, COLR_CUSTOM, NULL); +} + +/* Delete a character at the given position in string. */ +static void getstr_del_char(struct getstr_status *st) +{ + char *str = st->s + st->ci[st->pos].offset; + int cl = st->ci[st->pos + 1].offset - st->ci[st->pos].offset; + int cw = st->ci[st->pos + 1].dpyoff - st->ci[st->pos].dpyoff; + int i; + + memmove(str, str + cl, strlen(str) + 1); + + st->len--; + for (i = st->pos; i <= st->len; i++) { + st->ci[i].offset = st->ci[i + 1].offset - cl; + st->ci[i].dpyoff = st->ci[i + 1].dpyoff - cw; + } +} + +/* Add a character at the given position in string. */ +static void getstr_ins_char(struct getstr_status *st, char *c) +{ + char *str = st->s + st->ci[st->pos].offset; + int cl = UTF8_LENGTH(c[0]); + int cw = utf8_width(c); + int i; + + memmove(str + cl, str, strlen(str) + 1); + for (i = 0; i < cl; i++, str++) + *str = c[i]; + + for (i = st->len; i >= st->pos; i--) { + st->ci[i + 1].offset = st->ci[i].offset + cl; + st->ci[i + 1].dpyoff = st->ci[i].dpyoff + cw; + } + st->len++; +} + +static void bell(void) +{ + putchar('\a'); +} + +/* Initialize getstring data structure. */ +static void +getstr_init(struct getstr_status *st, char *str, struct getstr_charinfo *ci) +{ + int width; + + st->s = str; + st->ci = ci; + + st->len = width = 0; + while (*str) { + st->ci[st->len].offset = str - st->s; + st->ci[st->len].dpyoff = width; + + st->len++; + width += utf8_width(str); + str += UTF8_LENGTH(*str); + } + st->ci[st->len].offset = str - st->s; + st->ci[st->len].dpyoff = width; + + st->pos = st->len; + st->scrpos = 0; +} + +/* Scroll left/right if the cursor moves outside the window range. */ +static void getstr_fixscr(struct getstr_status *st) +{ + const int pgsize = col / 3; + int pgskip; + + while (st->pos < st->scrpos) { + pgskip = 0; + while (pgskip < pgsize && st->scrpos > 0) { + st->scrpos--; + pgskip += st->ci[st->scrpos + 1].dpyoff - st->ci[st->scrpos].dpyoff; + } + } + while (st->ci[st->pos].dpyoff - st->ci[st->scrpos].dpyoff > col - 2) { + pgskip = 0; + while (pgskip < pgsize && st->scrpos < st->len) { + pgskip += st->ci[st->scrpos + 1].dpyoff - st->ci[st->scrpos].dpyoff; + st->scrpos++; + } + } +} + +/* + * Getstring allows to get user input and to print it on a window, + * even if noecho() is on. This function is also used to modify an existing + * text (the variable string can be non-NULL). + * We need to do the echoing manually because of the multi-threading + * environment, otherwise the cursor would move from place to place without + * control. + */ +enum getstr getstring(WINDOW * win, char *str, int l, int x, int y) +{ + struct getstr_status st; + struct getstr_charinfo ci[l + 1]; + + int ch, k; + char c[UTF8_MAXLEN]; + + getstr_init(&st, str, ci); + custom_apply_attr(win, ATTR_HIGHEST); + + for (;;) { + getstr_fixscr(&st); + getstr_print(win, x, y, &st); + wins_doupdate(); + + if ((ch = wgetch(win)) == '\n') + break; + switch (ch) { + case KEY_BACKSPACE: /* delete one character */ + case 330: + case 127: + case CTRL('H'): + if (st.pos > 0) { + st.pos--; + getstr_del_char(&st); + } else + bell(); + break; + case CTRL('D'): /* delete next character */ + if (st.pos < st.len) + getstr_del_char(&st); + else + bell(); + break; + case CTRL('W'): /* delete a word */ + if (st.pos > 0) { + while (st.pos && st.s[st.ci[st.pos - 1].offset] == ' ') { + st.pos--; + getstr_del_char(&st); + } + while (st.pos && st.s[st.ci[st.pos - 1].offset] != ' ') { + st.pos--; + getstr_del_char(&st); + } + } else + bell(); + break; + case CTRL('K'): /* delete to end-of-line */ + st.s[st.ci[st.pos].offset] = 0; + st.len = st.pos; + break; + case CTRL('A'): /* go to begginning of string */ + st.pos = 0; + break; + case CTRL('E'): /* go to end of string */ + st.pos = st.len; + break; + case KEY_LEFT: /* move one char backward */ + case CTRL('B'): + if (st.pos > 0) + st.pos--; + break; + case KEY_RIGHT: /* move one char forward */ + case CTRL('F'): + if (st.pos < st.len) + st.pos++; + break; + case ESCAPE: /* cancel editing */ + return GETSTRING_ESC; + break; + default: /* insert one character */ + c[0] = ch; + for (k = 1; k < MIN(UTF8_LENGTH(c[0]), UTF8_MAXLEN); k++) + c[k] = (unsigned char)wgetch(win); + if (st.ci[st.len].offset + k < l) { + getstr_ins_char(&st, c); + st.pos++; + } + } + } + + custom_remove_attr(win, ATTR_HIGHEST); + + return st.len == 0 ? GETSTRING_RET : GETSTRING_VALID; +} + +/* Update an already existing string. */ +int updatestring(WINDOW * win, char **str, int x, int y) +{ + int len = strlen(*str); + char *buf; + enum getstr ret; + + EXIT_IF(len + 1 > BUFSIZ, _("Internal error: line too long")); + + buf = mem_malloc(BUFSIZ); + memcpy(buf, *str, len + 1); + + ret = getstring(win, buf, BUFSIZ, x, y); + + if (ret == GETSTRING_VALID) { + len = strlen(buf); + *str = mem_realloc(*str, len + 1, 1); + EXIT_IF(*str == NULL, _("out of memory")); + memcpy(*str, buf, len + 1); + } + + mem_free(buf); + return ret; +} @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -48,14 +48,14 @@ typedef struct { char text[HELPTEXTSIZ]; } help_page_t; -typedef enum -{ +typedef enum { HELP_MAIN, HELP_SAVE, HELP_IMPORT, HELP_EXPORT, HELP_DISPLACEMENT, HELP_VIEW, + HELP_PIPE, HELP_TAB, HELP_GOTO, HELP_DELETE, @@ -73,21 +73,18 @@ typedef enum HELP_CREDITS, HELPSCREENS, NOPAGE -} -help_pages_e; +} help_pages_e; /* Returns the number of lines in an help text. */ -static int -get_help_lines (char *text) +static int get_help_lines(char *text) { int i, newline; newline = 0; - for (i = 0; text[i]; i++) - { - if (text[i] == '\n') - newline++; - } + for (i = 0; text[i]; i++) { + if (text[i] == '\n') + newline++; + } return newline + 1; } @@ -96,54 +93,52 @@ get_help_lines (char *text) * of lines that were written. */ static int -help_write_pad (struct window *win, char *title, char *text, enum key action) +help_write_pad(struct window *win, char *title, char *text, enum key action) { int colnum, rownum; - char *bindings_title = "key bindings: %s"; + const char *bindings_title = "key bindings: %s"; char *bindings; colnum = 0; rownum = 0; - erase_window_part (win->p, rownum, colnum, BUFSIZ, win->w); - custom_apply_attr (win->p, ATTR_HIGHEST); - mvwprintw (win->p, rownum, colnum, "%s", title); - if ((int) action != KEY_RESIZE && action < NBKEYS) { - switch (action) - { - case KEY_END_OF_WEEK: - case KEY_START_OF_WEEK: - case KEY_MOVE_UP: - case KEY_MOVE_DOWN: - case KEY_MOVE_RIGHT: - case KEY_MOVE_LEFT: - case KEY_GENERIC_HELP: - case KEY_GENERIC_REDRAW: - case KEY_GENERIC_ADD_APPT: - case KEY_GENERIC_ADD_TODO: - case KEY_GENERIC_NEXT_DAY: - case KEY_GENERIC_PREV_DAY: - case KEY_GENERIC_NEXT_WEEK: - case KEY_GENERIC_PREV_WEEK: - case KEY_GENERIC_GOTO_TODAY: - case KEY_GENERIC_CREDITS: - case KEY_GENERIC_CUT: - case KEY_GENERIC_PASTE: - break; - default: - bindings = keys_action_allkeys (action); - - if (bindings) - { - colnum = win->w - strlen (bindings_title) - strlen (bindings); - mvwprintw (win->p, rownum, colnum, bindings_title, bindings); - } + erase_window_part(win->p, rownum, colnum, BUFSIZ, win->w); + custom_apply_attr(win->p, ATTR_HIGHEST); + mvwprintw(win->p, rownum, colnum, "%s", title); + if ((int)action != KEY_RESIZE && action < NBKEYS) { + switch (action) { + case KEY_END_OF_WEEK: + case KEY_START_OF_WEEK: + case KEY_MOVE_UP: + case KEY_MOVE_DOWN: + case KEY_MOVE_RIGHT: + case KEY_MOVE_LEFT: + case KEY_GENERIC_HELP: + case KEY_GENERIC_REDRAW: + case KEY_GENERIC_ADD_APPT: + case KEY_GENERIC_ADD_TODO: + case KEY_GENERIC_NEXT_DAY: + case KEY_GENERIC_PREV_DAY: + case KEY_GENERIC_NEXT_WEEK: + case KEY_GENERIC_PREV_WEEK: + case KEY_GENERIC_GOTO_TODAY: + case KEY_GENERIC_CREDITS: + case KEY_GENERIC_CUT: + case KEY_GENERIC_PASTE: + break; + default: + bindings = keys_action_allkeys(action); + + if (bindings) { + colnum = win->w - strlen(bindings_title) - strlen(bindings); + mvwprintw(win->p, rownum, colnum, bindings_title, bindings); } + } } colnum = 0; - rownum += get_help_lines (title); - custom_remove_attr (win->p, ATTR_HIGHEST); - mvwprintw (win->p, rownum, colnum, "%s", text); - rownum += get_help_lines (text); + rownum += get_help_lines(title); + custom_remove_attr(win->p, ATTR_HIGHEST); + mvwprintw(win->p, rownum, colnum, "%s", text); + rownum += get_help_lines(text); return rownum; } @@ -151,8 +146,7 @@ help_write_pad (struct window *win, char *title, char *text, enum key action) * Create and init help screen and its pad, which is used to make the scrolling * faster. */ -void -help_wins_init (struct scrollwin *hwin, int x, int y, int h, int w) +void help_wins_init(struct scrollwin *hwin, int x, int y, int h, int w) { const int PADOFFSET = 4; const int TITLELINES = 3; @@ -167,159 +161,158 @@ help_wins_init (struct scrollwin *hwin, int x, int y, int h, int w) hwin->pad.h = BUFSIZ; hwin->pad.w = hwin->win.w - 2 * PADOFFSET + 1; - (void)snprintf (hwin->label, BUFSIZ, _("Calcurse help")); - wins_scrollwin_init (hwin); - wins_show (hwin->win.p, hwin->label); + hwin->label = _("Calcurse help"); + wins_scrollwin_init(hwin); + wins_show(hwin->win.p, hwin->label); } /* * Delete the existing windows and recreate them with their new * size and placement. */ -static void -help_wins_reinit (struct scrollwin *hwin) +static void help_wins_reinit(struct scrollwin *hwin) { - wins_scrollwin_delete (hwin); - wins_get_config (); - help_wins_init (hwin, 0, 0, (notify_bar ()) ? row - 3 : row - 2, col); + wins_scrollwin_delete(hwin); + wins_get_config(); + help_wins_init(hwin, 0, 0, (notify_bar())? row - 3 : row - 2, col); } /* Reset the screen, needed when resizing terminal for example. */ -static void -help_wins_reset (struct scrollwin *hwin) +static void help_wins_reset(struct scrollwin *hwin) { - endwin (); - wins_refresh (); - curs_set (0); - delwin (win[STA].p); - help_wins_reinit (hwin); - win[STA].p = newwin (win[STA].h, win[STA].w, win[STA].y, win[STA].x); - keypad (win[STA].p, TRUE); - if (notify_bar ()) - notify_reinit_bar (); - wins_status_bar (); - if (notify_bar ()) - notify_update_bar (); + endwin(); + wins_refresh(); + curs_set(0); + delwin(win[STA].p); + help_wins_reinit(hwin); + win[STA].p = newwin(win[STA].h, win[STA].w, win[STA].y, win[STA].x); + keypad(win[STA].p, TRUE); + if (notify_bar()) + notify_reinit_bar(); + wins_status_bar(); + if (notify_bar()) + notify_update_bar(); } /* Association between a key pressed and its corresponding help page. */ -static int -wanted_page (int ch) +static int wanted_page(int ch) { int page; - switch (ch) - { - - case KEY_GENERIC_HELP: - page = HELP_MAIN; - break; - - case KEY_FLAG_ITEM: - page = HELP_FLAG; - break; - - case KEY_GENERIC_REDRAW: - case KEY_GENERIC_ADD_APPT: - case KEY_GENERIC_ADD_TODO: - case KEY_GENERIC_NEXT_DAY: - case KEY_GENERIC_PREV_DAY: - case KEY_GENERIC_NEXT_WEEK: - case KEY_GENERIC_PREV_WEEK: - case KEY_GENERIC_GOTO_TODAY: - page = HELP_GENERAL; - break; - - case KEY_GENERIC_SAVE: - page = HELP_SAVE; - break; - - case KEY_GENERIC_IMPORT: - page = HELP_IMPORT; - break; - - case KEY_GENERIC_EXPORT: - page = HELP_EXPORT; - break; - - case KEY_END_OF_WEEK: - case KEY_START_OF_WEEK: - case KEY_MOVE_UP: - case KEY_MOVE_DOWN: - case KEY_MOVE_RIGHT: - case KEY_MOVE_LEFT: - page = HELP_DISPLACEMENT; - break; - - case KEY_ADD_ITEM: - page = HELP_ADD; - break; - - case KEY_GENERIC_GOTO: - page = HELP_GOTO; - break; - - case KEY_DEL_ITEM: - page = HELP_DELETE; - break; - - case KEY_GENERIC_CUT: - case KEY_GENERIC_PASTE: - page = HELP_CUT_PASTE; - break; - - case KEY_EDIT_ITEM: - page = HELP_EDIT; - break; - - case KEY_EDIT_NOTE: - page = HELP_ENOTE; - break; - - case KEY_VIEW_NOTE: - page = HELP_VNOTE; - break; - - case KEY_GENERIC_CONFIG_MENU: - page = HELP_CONFIG; - break; - - case KEY_GENERIC_OTHER_CMD: - page = HELP_OTHER; - break; - - case KEY_REPEAT_ITEM: - page = HELP_REPEAT; - break; - - case KEY_VIEW_ITEM: - page = HELP_VIEW; - break; - - case KEY_RAISE_PRIORITY: - case KEY_LOWER_PRIORITY: - page = HELP_PRIORITY; - break; - - case KEY_GENERIC_CHANGE_VIEW: - page = HELP_TAB; - break; - - case KEY_GENERIC_CREDITS: - page = HELP_CREDITS; - break; - - default: - page = NOPAGE; - break; - } + switch (ch) { + + case KEY_GENERIC_HELP: + page = HELP_MAIN; + break; + + case KEY_FLAG_ITEM: + page = HELP_FLAG; + break; + + case KEY_GENERIC_REDRAW: + case KEY_GENERIC_ADD_APPT: + case KEY_GENERIC_ADD_TODO: + case KEY_GENERIC_NEXT_DAY: + case KEY_GENERIC_PREV_DAY: + case KEY_GENERIC_NEXT_WEEK: + case KEY_GENERIC_PREV_WEEK: + case KEY_GENERIC_GOTO_TODAY: + page = HELP_GENERAL; + break; + + case KEY_GENERIC_SAVE: + page = HELP_SAVE; + break; + + case KEY_GENERIC_IMPORT: + page = HELP_IMPORT; + break; + + case KEY_GENERIC_EXPORT: + page = HELP_EXPORT; + break; + + case KEY_END_OF_WEEK: + case KEY_START_OF_WEEK: + case KEY_MOVE_UP: + case KEY_MOVE_DOWN: + case KEY_MOVE_RIGHT: + case KEY_MOVE_LEFT: + page = HELP_DISPLACEMENT; + break; + + case KEY_ADD_ITEM: + page = HELP_ADD; + break; + + case KEY_GENERIC_GOTO: + page = HELP_GOTO; + break; + + case KEY_DEL_ITEM: + page = HELP_DELETE; + break; + + case KEY_GENERIC_CUT: + case KEY_GENERIC_PASTE: + page = HELP_CUT_PASTE; + break; + + case KEY_EDIT_ITEM: + page = HELP_EDIT; + break; + + case KEY_EDIT_NOTE: + page = HELP_ENOTE; + break; + + case KEY_VIEW_NOTE: + page = HELP_VNOTE; + break; + + case KEY_GENERIC_CONFIG_MENU: + page = HELP_CONFIG; + break; + + case KEY_GENERIC_OTHER_CMD: + page = HELP_OTHER; + break; + + case KEY_REPEAT_ITEM: + page = HELP_REPEAT; + break; + + case KEY_VIEW_ITEM: + page = HELP_VIEW; + break; + + case KEY_PIPE_ITEM: + page = HELP_PIPE; + break; + + case KEY_RAISE_PRIORITY: + case KEY_LOWER_PRIORITY: + page = HELP_PRIORITY; + break; + + case KEY_GENERIC_CHANGE_VIEW: + page = HELP_TAB; + break; + + case KEY_GENERIC_CREDITS: + page = HELP_CREDITS; + break; + + default: + page = NOPAGE; + break; + } - return (page); + return page; } /* Draws the help screen */ -void -help_screen (void) +void help_screen(void) { enum { MOVE_UP, @@ -336,452 +329,460 @@ help_screen (void) char keystr[DIRECTIONS][BUFSIZ]; hscr[HELP_MAIN].title = - _(" Welcome to Calcurse. This is the main help screen.\n"); - (void)snprintf (hscr[HELP_MAIN].text, HELPTEXTSIZ, - _("Moving around: Press '%s' or '%s' to scroll text upward or downward\n" - " inside help screens, if necessary.\n\n" - " Exit help: When finished, press '%s' to exit help and go back to\n" - " the main Calcurse screen.\n\n" - " Help topic: At the bottom of this screen you can see a panel with\n" - " different fields, represented by a letter and a short\n" - " title. This panel contains all the available actions\n" - " you can perform when using Calcurse.\n" - " By pressing one of the letters appearing in this\n" - " panel, you will be shown a short description of the\n" - " corresponding action. At the top right side of the\n" - " description screen are indicated the user-defined key\n" - " bindings that lead to the action.\n\n" - " Credits: Press '%s' for credits."), - keys_action_firstkey (KEY_GENERIC_SCROLL_UP), - keys_action_firstkey (KEY_GENERIC_SCROLL_DOWN), - keys_action_firstkey (KEY_GENERIC_QUIT), - keys_action_firstkey (KEY_GENERIC_CREDITS)); + _(" Welcome to Calcurse. This is the main help screen.\n"); + snprintf(hscr[HELP_MAIN].text, HELPTEXTSIZ, + _ + ("Moving around: Press '%s' or '%s' to scroll text upward or downward\n" + " inside help screens, if necessary.\n\n" + " Exit help: When finished, press '%s' to exit help and go back to\n" + " the main Calcurse screen.\n\n" + " Help topic: At the bottom of this screen you can see a panel with\n" + " different fields, represented by a letter and a short\n" + " title. This panel contains all the available actions\n" + " you can perform when using Calcurse.\n" + " By pressing one of the letters appearing in this\n" + " panel, you will be shown a short description of the\n" + " corresponding action. At the top right side of the\n" + " description screen are indicated the user-defined key\n" + " bindings that lead to the action.\n\n" + " Credits: Press '%s' for credits."), + keys_action_firstkey(KEY_GENERIC_SCROLL_UP), + keys_action_firstkey(KEY_GENERIC_SCROLL_DOWN), + keys_action_firstkey(KEY_GENERIC_QUIT), + keys_action_firstkey(KEY_GENERIC_CREDITS)); hscr[HELP_SAVE].title = _("Save\n"); - (void)snprintf (hscr[HELP_SAVE].text, HELPTEXTSIZ, - _("Save calcurse data.\n" - "Data are splitted into four different files which contain :" - "\n\n" - " / ~/.calcurse/conf -> user configuration\n" - " | (layout, color, general options)\n" - " | ~/.calcurse/apts -> data related to the appointments\n" - " | ~/.calcurse/todo -> data related to the todo list\n" - " \\ ~/.calcurse/keys -> user-defined key bindings\n" - "\nIn the config menu, you can choose to save the Calcurse data\n" - "automatically before quitting.")); + snprintf(hscr[HELP_SAVE].text, HELPTEXTSIZ, + _("Save calcurse data.\n" + "Data are splitted into four different files which contain :" + "\n\n" + " / ~/.calcurse/conf -> user configuration\n" + " | (layout, color, general options)\n" + " | ~/.calcurse/apts -> data related to the appointments\n" + " | ~/.calcurse/todo -> data related to the todo list\n" + " \\ ~/.calcurse/keys -> user-defined key bindings\n" + "\nIn the config menu, you can choose to save the Calcurse data\n" + "automatically before quitting.")); hscr[HELP_IMPORT].title = _("Import\n"); - (void)snprintf (hscr[HELP_IMPORT].text, HELPTEXTSIZ, - _("Import data from an icalendar file.\n" - "You will be asked to enter the file name from which to load ical\n" - "items. At the end of the import process, and if the general option\n" - "'skip_system_dialogs' is not set to 'yes', a report indicating how\n" - "many items were imported is shown.\n" - "This report contains the total number of lines read, the number of\n" - "appointments, events and todo items which were successfully imported,\n" - "together with the number of items for which problems occured and that\n" - "were skipped, if any.\n\n" - "If one or more items could not be imported, one has the possibility to\n" - "read the import process report in order to identify which problems\n" - "occured.\n" - "In this report is shown one item per line, with the line in the input\n" - "stream at which this item begins, together with the description of why\n" - "the item could not be imported.\n")); + snprintf(hscr[HELP_IMPORT].text, HELPTEXTSIZ, + _("Import data from an icalendar file.\n" + "You will be asked to enter the file name from which to load ical\n" + "items. At the end of the import process, and if the general option\n" + "'system_dialogs' is set to 'yes', a report indicating how many items\n" + "were imported is shown.\n" + "This report contains the total number of lines read, the number of\n" + "appointments, events and todo items which were successfully imported,\n" + "together with the number of items for which problems occured and that\n" + "were skipped, if any.\n\n" + "If one or more items could not be imported, one has the possibility to\n" + "read the import process report in order to identify which problems\n" + "occured.\n" + "In this report is shown one item per line, with the line in the input\n" + "stream at which this item begins, together with the description of why\n" + "the item could not be imported.\n")); hscr[HELP_EXPORT].title = _("Export\n"); - (void)snprintf (hscr[HELP_EXPORT].text, HELPTEXTSIZ, - _("Export calcurse data (appointments, events and todos).\n" - "This leads to the export submenu, from which you can choose between\n" - "two different export formats: 'ical' and 'pcal'. Choosing one of\n" - "those formats lets you export calcurse data to icalendar or pcal\n" - "format.\n\n" - "You first need to specify the file to which the data will be exported.\n" - "By default, this file is:\n\n" - " ~/calcurse.ics\n\n" - "for an ical export, and:\n\n" - " ~/calcurse.txt\n\n" - "for a pcal export.\n\n" - "Calcurse data are exported in the following order:\n" - " events, appointments, todos.\n")); - - (void)strncpy (keystr[MOVE_UP], keys_action_allkeys (KEY_MOVE_UP), BUFSIZ); - (void)strncpy (keystr[MOVE_DOWN], keys_action_allkeys (KEY_MOVE_DOWN), - BUFSIZ); - (void)strncpy (keystr[MOVE_LEFT], keys_action_allkeys (KEY_MOVE_LEFT), - BUFSIZ); - (void)strncpy (keystr[MOVE_RIGHT], keys_action_allkeys (KEY_MOVE_RIGHT), - BUFSIZ); + snprintf(hscr[HELP_EXPORT].text, HELPTEXTSIZ, + _("Export calcurse data (appointments, events and todos).\n" + "This leads to the export submenu, from which you can choose between\n" + "two different export formats: 'ical' and 'pcal'. Choosing one of\n" + "those formats lets you export calcurse data to icalendar or pcal\n" + "format.\n\n" + "You first need to specify the file to which the data will be exported.\n" + "By default, this file is:\n\n" + " ~/calcurse.ics\n\n" + "for an ical export, and:\n\n" + " ~/calcurse.txt\n\n" + "for a pcal export.\n\n" + "Calcurse data are exported in the following order:\n" + " events, appointments, todos.\n")); + + strncpy(keystr[MOVE_UP], keys_action_allkeys(KEY_MOVE_UP), BUFSIZ); + strncpy(keystr[MOVE_DOWN], keys_action_allkeys(KEY_MOVE_DOWN), BUFSIZ); + strncpy(keystr[MOVE_LEFT], keys_action_allkeys(KEY_MOVE_LEFT), BUFSIZ); + strncpy(keystr[MOVE_RIGHT], keys_action_allkeys(KEY_MOVE_RIGHT), BUFSIZ); hscr[HELP_DISPLACEMENT].title = _("Displacement keys\n"); - (void)snprintf (hscr[HELP_DISPLACEMENT].text, HELPTEXTSIZ, - _("Move around inside calcurse screens.\n" - "The following scheme summarizes how to get around:\n\n" - " move up\n" - " move to previous week\n" - "\n" - " %s\n" - " move left ^ \n" - " move to previous day |\n" - " %s\n" - " <-- + -->\n" - " %s\n" - " | move right\n" - " v move to next day\n" - " %s\n" - "\n" - " move to next week\n" - " move down\n" - "\nMoreover, while inside the calendar panel, the '%s' key moves\n" - "to the first day of the week, and the '%s' key selects the last day of\n" - "the week.\n"), - keystr[MOVE_UP], keystr[MOVE_LEFT], - keystr[MOVE_RIGHT], keystr[MOVE_DOWN], - keys_action_firstkey (KEY_START_OF_WEEK), - keys_action_firstkey (KEY_END_OF_WEEK)); + snprintf(hscr[HELP_DISPLACEMENT].text, HELPTEXTSIZ, + _("Move around inside calcurse screens.\n" + "The following scheme summarizes how to get around:\n\n" + " move up\n" + " move to previous week\n" + "\n" + " %s\n" + " move left ^ \n" + " move to previous day |\n" + " %s\n" + " <-- + -->\n" + " %s\n" + " | move right\n" + " v move to next day\n" + " %s\n" + "\n" + " move to next week\n" + " move down\n" + "\nMoreover, while inside the calendar panel, the '%s' key moves\n" + "to the first day of the week, and the '%s' key selects the last day of\n" + "the week.\n"), + keystr[MOVE_UP], keystr[MOVE_LEFT], + keystr[MOVE_RIGHT], keystr[MOVE_DOWN], + keys_action_firstkey(KEY_START_OF_WEEK), + keys_action_firstkey(KEY_END_OF_WEEK)); hscr[HELP_VIEW].title = _("View\n"); - (void)snprintf (hscr[HELP_VIEW].text, HELPTEXTSIZ, - _("View the item you select in either the Todo or Appointment panel.\n" - "\nThis is usefull when an event description is longer than the " - "available\nspace to display it. " - "If that is the case, the description will be\n" - "shortened and its end replaced by '...'. To be able to read the entire\n" - "description, just press '%s' and a popup window will appear, containing\n" - "the whole event.\n" - "\nPress any key to close the popup window and go back to the main\n" - "Calcurse screen."), - keys_action_firstkey (KEY_VIEW_ITEM)); + snprintf(hscr[HELP_VIEW].text, HELPTEXTSIZ, + _ + ("View the item you select in either the Todo or Appointment panel.\n" + "\nThis is usefull when an event description is longer than the " + "available\nspace to display it. " + "If that is the case, the description will be\n" + "shortened and its end replaced by '...'. To be able to read the entire\n" + "description, just press '%s' and a popup window will appear, containing\n" + "the whole event.\n" + "\nPress any key to close the popup window and go back to the main\n" + "Calcurse screen."), keys_action_firstkey(KEY_VIEW_ITEM)); + + hscr[HELP_PIPE].title = _("Pipe\n"); + snprintf(hscr[HELP_PIPE].text, HELPTEXTSIZ, + _("Pipe the selected item to an external program.\n" + "\nPress the '%s' key to pipe the currently selected appointment or\n" + "todo entry to an external program.\n" + "\nYou will be driven back to calcurse as soon as the program exits.\n"), + keys_action_firstkey(KEY_PIPE_ITEM)); hscr[HELP_TAB].title = _("Tab\n"); - (void)snprintf (hscr[HELP_TAB].text, HELPTEXTSIZ, - _("Switch between panels.\n" - "The panel currently in use has its border colorized.\n" - "\nSome actions are possible only if the right panel is selected.\n" - "For example, if you want to add a task in the TODO list, you need first" - "\nto press the '%s' key to get the TODO panel selected. Then you can\n" - "press '%s' to add your item.\n" - "\nNotice that at the bottom of the screen the list of possible actions\n" - "change while pressing '%s', so you always know what action can be\n" - "performed on the selected panel."), - keys_action_firstkey (KEY_GENERIC_CHANGE_VIEW), - keys_action_firstkey (KEY_ADD_ITEM), - keys_action_firstkey (KEY_GENERIC_CHANGE_VIEW)); + snprintf(hscr[HELP_TAB].text, HELPTEXTSIZ, + _("Switch between panels.\n" + "The panel currently in use has its border colorized.\n" + "\nSome actions are possible only if the right panel is selected.\n" + "For example, if you want to add a task in the TODO list, you need first" + "\nto press the '%s' key to get the TODO panel selected. Then you can\n" + "press '%s' to add your item.\n" + "\nNotice that at the bottom of the screen the list of possible actions\n" + "change while pressing '%s', so you always know what action can be\n" + "performed on the selected panel."), + keys_action_firstkey(KEY_GENERIC_CHANGE_VIEW), + keys_action_firstkey(KEY_ADD_ITEM), + keys_action_firstkey(KEY_GENERIC_CHANGE_VIEW)); hscr[HELP_GOTO].title = _("Goto\n"); - (void)snprintf (hscr[HELP_GOTO].text, HELPTEXTSIZ, - _("Jump to a specific day in the calendar.\n" - "\nUsing this command, you do not need to travel to that day using\n" - "the displacement keys inside the calendar panel.\n" - "If you hit [ENTER] without specifying any date, Calcurse checks the\n" - "system current date and you will be taken to that date.\n" - "\nNotice that pressing '%s', whatever panel is\n" - "selected, will select current day in the calendar."), - keys_action_firstkey (KEY_GENERIC_GOTO_TODAY)); + snprintf(hscr[HELP_GOTO].text, HELPTEXTSIZ, + _("Jump to a specific day in the calendar.\n" + "\nUsing this command, you do not need to travel to that day using\n" + "the displacement keys inside the calendar panel.\n" + "If you hit [ENTER] without specifying any date, Calcurse checks the\n" + "system current date and you will be taken to that date.\n" + "\nNotice that pressing '%s', whatever panel is\n" + "selected, will select current day in the calendar."), + keys_action_firstkey(KEY_GENERIC_GOTO_TODAY)); hscr[HELP_DELETE].title = _("Delete\n"); - (void)snprintf (hscr[HELP_DELETE].text, HELPTEXTSIZ, - _("Delete an element in the ToDo or Appointment list.\n" - "\nDepending on which panel is selected when you press the delete key,\n" - "the hilighted item of either the ToDo or Appointment list will be \n" - "removed from this list.\n" - "\nIf the item to be deleted is recurrent, you will be asked if you\n" - "wish to suppress all of the item occurences or just the one you\n" - "selected.\n" - "\nIf the general option 'confirm_delete' is set to 'YES', then you will" - "\nbe asked for confirmation before deleting the selected event.\n" - "Do not forget to save the calendar data to retrieve the modifications\n" - "next time you launch Calcurse.")); + snprintf(hscr[HELP_DELETE].text, HELPTEXTSIZ, + _("Delete an element in the ToDo or Appointment list.\n" + "\nDepending on which panel is selected when you press the delete key,\n" + "the hilighted item of either the ToDo or Appointment list will be \n" + "removed from this list.\n" + "\nIf the item to be deleted is recurrent, you will be asked if you\n" + "wish to suppress all of the item occurences or just the one you\n" + "selected.\n" + "\nIf the general option 'confirm_delete' is set to 'YES', then you will" + "\nbe asked for confirmation before deleting the selected event.\n" + "Do not forget to save the calendar data to retrieve the modifications\n" + "next time you launch Calcurse.")); hscr[HELP_ADD].title = _("Add\n"); - (void)snprintf (hscr[HELP_ADD].text, HELPTEXTSIZ, - _("Add an item in either the ToDo or Appointment list, depending on which\n" - "panel is selected when you press '%s'.\n" - "\nTo enter a new item in the TODO list, you will need first to enter the" - "\ndescription of this new item. Then you will be asked to specify the " - "todo\npriority. This priority is represented by a number going from 9 " - "for the\nlowest priority, to 1 for the highest one. It is still " - "possible to\nchange the item priority afterwards, by using the '%s' and " - "'%s' keys\ninside the todo panel.\n" - "\nIf the APPOINTMENT panel is selected while pressing '%s', you will be\n" - "able to enter either a new appointment or a new all-day long event.\n" - "To enter a new event, press [ENTER] instead of the item start time, " - "and\njust fill in the event description.\n" - "To enter a new appointment to be added in the APPOINTMENT list, you\n" - "will need to enter successively the time at which the appointment\n" - "begins, the appointment length (either by specifying the duration in\n" - "minutes, or the end time in [hh:mm] or [h:mm] format), and the\n" - "description of the event.\n" - "\nThe day at which occurs the event or appointment is the day currently" - "\nselected in the calendar, so you need to move to the desired day " - "before\npressing '%s'.\n" "\nNotes:\n" - " o if an appointment lasts for such a long time that it continues\n" - " on the next days, this event will be indicated on all the\n" - " corresponding days, and the beginning or ending hour will be\n" - " replaced by '..' if the event does not begin or end on the day.\n" - " o if you only press [ENTER] at the APPOINTMENT or TODO event\n" - " description prompt, without any description, no item will be\n" - " added.\n" - " o do not forget to save the calendar data to retrieve the new\n" - " event next time you launch Calcurse."), - keys_action_firstkey (KEY_ADD_ITEM), - keys_action_firstkey (KEY_RAISE_PRIORITY), - keys_action_firstkey (KEY_LOWER_PRIORITY), - keys_action_firstkey (KEY_ADD_ITEM), - keys_action_firstkey (KEY_ADD_ITEM)); + snprintf(hscr[HELP_ADD].text, HELPTEXTSIZ, + _ + ("Add an item in either the ToDo or Appointment list, depending on which\n" + "panel is selected when you press '%s'.\n" + "\nTo enter a new item in the TODO list, you will need first to enter the" + "\ndescription of this new item. Then you will be asked to specify the " + "todo\npriority. This priority is represented by a number going from 9 " + "for the\nlowest priority, to 1 for the highest one. It is still " + "possible to\nchange the item priority afterwards, by using the '%s' and " + "'%s' keys\ninside the todo panel.\n" + "\nIf the APPOINTMENT panel is selected while pressing '%s', you will be\n" + "able to enter either a new appointment or a new all-day long event.\n" + "To enter a new event, press [ENTER] instead of the item start time, " + "and\njust fill in the event description.\n" + "To enter a new appointment to be added in the APPOINTMENT list, you\n" + "will need to enter successively the time at which the appointment\n" + "begins, the appointment length (either by specifying the end time in\n" + "[hh:mm] or the duration in [+hh:mm], [+xxdxxhxxm] or [+mm] format), \n" + "and the description of the event.\n" + "\nThe day at which occurs the event or appointment is the day currently" + "\nselected in the calendar, so you need to move to the desired day " + "before\npressing '%s'.\n" "\nNotes:\n" + " o if an appointment lasts for such a long time that it continues\n" + " on the next days, this event will be indicated on all the\n" + " corresponding days, and the beginning or ending hour will be\n" + " replaced by '..' if the event does not begin or end on the day.\n" + " o if you only press [ENTER] at the APPOINTMENT or TODO event\n" + " description prompt, without any description, no item will be\n" + " added.\n" + " o do not forget to save the calendar data to retrieve the new\n" + " event next time you launch Calcurse."), + keys_action_firstkey(KEY_ADD_ITEM), + keys_action_firstkey(KEY_RAISE_PRIORITY), + keys_action_firstkey(KEY_LOWER_PRIORITY), + keys_action_firstkey(KEY_ADD_ITEM), + keys_action_firstkey(KEY_ADD_ITEM)); hscr[HELP_CUT_PASTE].title = _("Cut and Paste\n"); - (void)snprintf (hscr[HELP_CUT_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" - "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), - keys_action_firstkey (KEY_GENERIC_PASTE)); + snprintf(hscr[HELP_CUT_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" + "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), + keys_action_firstkey(KEY_GENERIC_PASTE)); hscr[HELP_EDIT].title = _("Edit Item\n"); - (void)snprintf (hscr[HELP_EDIT].text, HELPTEXTSIZ, - _("Edit the item which is currently selected.\n" - "Depending on the item type (appointment, event, or todo), and if it is\n" - "repeated or not, you will be asked to choose one of the item properties" - "\nto modify. An item property is one of the following: the start time, " - "the\nend time, the description, or the item repetition.\n" - "Once you have chosen the property you want to modify, you will be shown" - "\nits actual value, and you will be able to change it as you like.\n" - "\nNotes:\n" - " o if you choose to edit the item repetition properties, you will\n" - " be asked to re-enter all of the repetition characteristics\n" - " (repetition type, frequence, and ending date). Moreover, the\n" - " previous data concerning the deleted occurences will be lost.\n" - " o do not forget to save the calendar data to retrieve the\n" - " modified properties next time you launch Calcurse.")); + snprintf(hscr[HELP_EDIT].text, HELPTEXTSIZ, + _("Edit the item which is currently selected.\n" + "Depending on the item type (appointment, event, or todo), and if it is\n" + "repeated or not, you will be asked to choose one of the item properties" + "\nto modify. An item property is one of the following: the start time, " + "the\nend time, the description, or the item repetition.\n" + "Once you have chosen the property you want to modify, you will be shown" + "\nits actual value, and you will be able to change it as you like.\n" + "\nNotes:\n" + " o if you choose to edit the item repetition properties, you will\n" + " be asked to re-enter all of the repetition characteristics\n" + " (repetition type, frequence, and ending date). Moreover, the\n" + " previous data concerning the deleted occurences will be lost.\n" + " o do not forget to save the calendar data to retrieve the\n" + " modified properties next time you launch Calcurse.")); hscr[HELP_ENOTE].title = _("EditNote\n"); - (void)snprintf (hscr[HELP_ENOTE].text, HELPTEXTSIZ, - _("Attach a note to any type of item, or edit an already existing note.\n" - "This feature is useful if you do not have enough space to store all\n" - "of your item description, or if you would like to add sub-tasks to an\n" - "already existing todo item for example.\n" - "Before pressing the '%s' key, you first need to highlight the item you\n" - "want the note to be attached to. Then you will be driven to an\n" - "external editor to edit your note. This editor is chosen the following\n" - "way:\n" - " o if the 'VISUAL' environment variable is set, then this will be\n" - " the default editor to be called.\n" - " o if 'VISUAL' is not set, then the 'EDITOR' environment variable\n" - " will be used as the default editor.\n" - " o if none of the above environment variables is set, then\n" - " '/usr/bin/vi' will be used.\n" - "\nOnce the item note is edited and saved, quit your favorite editor.\n" - "You will then go back to Calcurse, and the '>' sign will appear in front" - "\nof the highlighted item, meaning there is a note attached to it."), - keys_action_firstkey (KEY_EDIT_NOTE)); + snprintf(hscr[HELP_ENOTE].text, HELPTEXTSIZ, + _ + ("Attach a note to any type of item, or edit an already existing note.\n" + "This feature is useful if you do not have enough space to store all\n" + "of your item description, or if you would like to add sub-tasks to an\n" + "already existing todo item for example.\n" + "Before pressing the '%s' key, you first need to highlight the item you\n" + "want the note to be attached to. Then you will be driven to an\n" + "external editor to edit your note. This editor is chosen the following\n" + "way:\n" + " o if the 'VISUAL' environment variable is set, then this will be\n" + " the default editor to be called.\n" + " o if 'VISUAL' is not set, then the 'EDITOR' environment variable\n" + " will be used as the default editor.\n" + " o if none of the above environment variables is set, then\n" + " '/usr/bin/vi' will be used.\n" + "\nOnce the item note is edited and saved, quit your favorite editor.\n" + "You will then go back to Calcurse, and the '>' sign will appear in front" + "\nof the highlighted item, meaning there is a note attached to it."), + keys_action_firstkey(KEY_EDIT_NOTE)); hscr[HELP_VNOTE].title = _("ViewNote\n"); - (void)snprintf (hscr[HELP_VNOTE].text, HELPTEXTSIZ, - _("View a note which was previously attached to an item (an item which\n" - "owns a note has a '>' sign in front of it).\n" - "This command only permits to view the note, not to edit it (to do so,\n" - "use the 'EditNote' command, by pressing the '%s' key).\n" - "Once you highlighted an item with a note attached to it, and the '%s' key" - "\nwas pressed, you will be driven to an external pager to view that " - "note.\n" - "The default pager is chosen the following way:\n" - " o if the 'PAGER' environment variable is set, then this will be\n" - " the default viewer to be called.\n" - " o if the above environment variable is not set, then\n" - " '/usr/bin/less' will be used.\n" - "As for editing a note, quit the pager and you will be driven back to\n" - "Calcurse."), - keys_action_firstkey (KEY_EDIT_NOTE), - keys_action_firstkey (KEY_VIEW_NOTE)); + snprintf(hscr[HELP_VNOTE].text, HELPTEXTSIZ, + _ + ("View a note which was previously attached to an item (an item which\n" + "owns a note has a '>' sign in front of it).\n" + "This command only permits to view the note, not to edit it (to do so,\n" + "use the 'EditNote' command, by pressing the '%s' key).\n" + "Once you highlighted an item with a note attached to it, and the '%s' key" + "\nwas pressed, you will be driven to an external pager to view that " + "note.\n" "The default pager is chosen the following way:\n" + " o if the 'PAGER' environment variable is set, then this will be\n" + " the default viewer to be called.\n" + " o if the above environment variable is not set, then\n" + " '/usr/bin/less' will be used.\n" + "As for editing a note, quit the pager and you will be driven back to\n" + "Calcurse."), keys_action_firstkey(KEY_EDIT_NOTE), + keys_action_firstkey(KEY_VIEW_NOTE)); hscr[HELP_PRIORITY].title = _("Priority\n"); - (void)snprintf (hscr[HELP_PRIORITY].text, HELPTEXTSIZ, - _("Change the priority of the currently selected item in the ToDo list.\n" - "Priorities are represented by the number appearing in front of the\n" - "todo description. This number goes from 9 for the lowest priority to\n" - "1 for the highest priority.\n" - "Todo having higher priorities are placed first (at the top) inside the\n" - "todo panel.\n\n" - "If you want to raise the priority of a todo item, you need to press " - "'%s'.\n" - "In doing so, the number in front of this item will decrease, " - "meaning its\npriority increases. The item position inside the todo " - "panel may change,\ndepending on the priority of the items above it.\n\n" - "At the opposite, to lower a todo priority, press '%s'. The todo position" - "\nmay also change depending on the priority of the items below."), - keys_action_firstkey (KEY_RAISE_PRIORITY), - keys_action_firstkey (KEY_LOWER_PRIORITY)); + snprintf(hscr[HELP_PRIORITY].text, HELPTEXTSIZ, + _ + ("Change the priority of the currently selected item in the ToDo list.\n" + "Priorities are represented by the number appearing in front of the\n" + "todo description. This number goes from 9 for the lowest priority to\n" + "1 for the highest priority.\n" + "Todo having higher priorities are placed first (at the top) inside the\n" + "todo panel.\n\n" + "If you want to raise the priority of a todo item, you need to press " + "'%s'.\n" + "In doing so, the number in front of this item will decrease, " + "meaning its\npriority increases. The item position inside the todo " + "panel may change,\ndepending on the priority of the items above it.\n\n" + "At the opposite, to lower a todo priority, press '%s'. The todo position" + "\nmay also change depending on the priority of the items below."), + keys_action_firstkey(KEY_RAISE_PRIORITY), + keys_action_firstkey(KEY_LOWER_PRIORITY)); hscr[HELP_REPEAT].title = _("Repeat\n"); - (void)snprintf (hscr[HELP_REPEAT].text, HELPTEXTSIZ, - _("Repeat an event or an appointment.\n" - "You must first select the item to be repeated by moving inside the\n" - "appointment panel. Then pressing '%s' will lead you to a set of three\n" - "questions, with which you will be able to specify the repetition\n" - "characteristics:\n\n" - " o type: you can choose between a daily, weekly, monthly or\n" - " yearly repetition by pressing 'D', 'W', 'M' or 'Y'\n" - " respectively.\n\n" - " o frequence: this indicates how often the item shall be repeated.\n" - " For example, if you want to remember an anniversary,\n" - " choose a 'yearly' repetition with a frequence of '1',\n" - " which means it must be repeated every year. Another\n" - " example: if you go to the restaurant every two days,\n" - " choose a 'daily' repetition with a frequence of '2'.\n\n" - " o ending date: this specifies when to stop repeating the selected\n" - " event or appointment. To indicate an endless \n" - " repetition, enter '0' and the item will be repeated\n" - " forever.\n" "\nNotes:\n" - " o repeated items are marked with an '*' inside the appointment\n" - " panel, to be easily recognizable from non-repeated ones.\n" - " o the 'Repeat' and 'Delete' command can be mixed to create\n" - " complicated configurations, as it is possible to delete only\n" - " one occurence of a repeated item."), - keys_action_firstkey (KEY_REPEAT_ITEM)); + snprintf(hscr[HELP_REPEAT].text, HELPTEXTSIZ, + _("Repeat an event or an appointment.\n" + "You must first select the item to be repeated by moving inside the\n" + "appointment panel. Then pressing '%s' will lead you to a set of three\n" + "questions, with which you will be able to specify the repetition\n" + "characteristics:\n\n" + " o type: you can choose between a daily, weekly, monthly or\n" + " yearly repetition by pressing 'D', 'W', 'M' or 'Y'\n" + " respectively.\n\n" + " o frequence: this indicates how often the item shall be repeated.\n" + " For example, if you want to remember an anniversary,\n" + " choose a 'yearly' repetition with a frequence of '1',\n" + " which means it must be repeated every year. Another\n" + " example: if you go to the restaurant every two days,\n" + " choose a 'daily' repetition with a frequence of '2'.\n\n" + " o ending date: this specifies when to stop repeating the selected\n" + " event or appointment. To indicate an endless \n" + " repetition, enter '0' and the item will be repeated\n" + " forever.\n" "\nNotes:\n" + " o repeated items are marked with an '*' inside the appointment\n" + " panel, to be easily recognizable from non-repeated ones.\n" + " o the 'Repeat' and 'Delete' command can be mixed to create\n" + " complicated configurations, as it is possible to delete only\n" + " one occurence of a repeated item."), + keys_action_firstkey(KEY_REPEAT_ITEM)); hscr[HELP_FLAG].title = _("Flag Item\n"); - (void)snprintf (hscr[HELP_FLAG].text, HELPTEXTSIZ, - _("Toggle an appointment's 'important' flag or a todo's 'completed' flag.\n" - "If a todo is flagged as completed, its priority number will be replaced\n" - "by an 'X' sign. Completed tasks will no longer appear in exported data\n" - "or when using the '-t' command line flag (unless specifying '0' as the\n" - "priority number, in which case only completed tasks will be shown).\n\n" - "If an appointment is flagged as important, an exclamation mark appears\n" - "in front of it, and you will be warned if time gets closed to the\n" - "appointment start time.\n" - "To customize the way one gets notified, the configuration submenu lets\n" - "you choose the command launched to warn user of an upcoming appointment," - "\nand how long before it he gets notified.")); + snprintf(hscr[HELP_FLAG].text, HELPTEXTSIZ, + _ + ("Toggle an appointment's 'important' flag or a todo's 'completed' flag.\n" + "If a todo is flagged as completed, its priority number will be replaced\n" + "by an 'X' sign. Completed tasks will no longer appear in exported data\n" + "or when using the '-t' command line flag (unless specifying '0' as the\n" + "priority number, in which case only completed tasks will be shown).\n\n" + "If an appointment is flagged as important, an exclamation mark appears\n" + "in front of it, and you will be warned if time gets closed to the\n" + "appointment start time.\n" + "To customize the way one gets notified, the configuration submenu lets\n" + "you choose the command launched to warn user of an upcoming appointment," + "\nand how long before it he gets notified.")); hscr[HELP_CONFIG].title = _("Config\n"); - (void)snprintf (hscr[HELP_CONFIG].text, HELPTEXTSIZ, - _("Open the configuration submenu.\n" - "From this submenu, you can select between color, layout, notification\n" - "and general options, and you can also configure your keybindings.\n" - "\nThe color submenu lets you choose the color theme.\n" - "The layout submenu lets you choose the Calcurse screen layout, in other" - "\nwords where to place the three different panels on the screen.\n" - "The general options submenu brings a screen with the different options" - "\nwhich modifies the way Calcurse interacts with the user.\n" - "The notify submenu allows you to change the notify-bar settings.\n" - "The keys submenu lets you define your own key bindings.\n" - "\nDo not forget to save the calendar data to retrieve your configuration" - "\nnext time you launch Calcurse.")); + snprintf(hscr[HELP_CONFIG].text, HELPTEXTSIZ, + _("Open the configuration submenu.\n" + "From this submenu, you can select between color, layout, notification\n" + "and general options, and you can also configure your keybindings.\n" + "\nThe color submenu lets you choose the color theme.\n" + "The layout submenu lets you choose the Calcurse screen layout, in other" + "\nwords where to place the three different panels on the screen.\n" + "The general options submenu brings a screen with the different options" + "\nwhich modifies the way Calcurse interacts with the user.\n" + "The notify submenu allows you to change the notify-bar settings.\n" + "The keys submenu lets you define your own key bindings.\n" + "\nDo not forget to save the calendar data to retrieve your configuration" + "\nnext time you launch Calcurse.")); hscr[HELP_GENERAL].title = _("Generic keybindings\n"); - (void)snprintf (hscr[HELP_GENERAL].text, HELPTEXTSIZ, - _("Some of the keybindings apply whatever panel is selected. They are\n" - "called generic keybinding.\n" - "Here is the list of all the generic key bindings, together with their\n" - "corresponding action:\n\n" - " '%s' : Redraw function -> redraws calcurse panels, this is useful if\n" - " you resize your terminal screen or when\n" - " garbage appears inside the display\n" - " '%s' : Add Appointment -> add an appointment or an event\n" - " '%s' : Add ToDo -> add a todo\n" - " '%s' : -1 Day -> move to previous day\n" - " '%s' : +1 Day -> move to next day\n" - " '%s' : -1 Week -> move to previous week\n" - " '%s' : +1 Week -> move to next week\n" - " '%s' : Goto today -> move to current day\n" - "\nThe '%s' and '%s' keys are used to scroll text upward or downward\n" - "when inside specific screens such the help screens for example.\n" - "They are also used when the calendar screen is selected to switch\n" - "between the available views (monthly and weekly calendar views)."), - keys_action_firstkey (KEY_GENERIC_REDRAW), - keys_action_firstkey (KEY_GENERIC_ADD_APPT), - keys_action_firstkey (KEY_GENERIC_ADD_TODO), - keys_action_firstkey (KEY_GENERIC_PREV_DAY), - keys_action_firstkey (KEY_GENERIC_NEXT_DAY), - keys_action_firstkey (KEY_GENERIC_PREV_WEEK), - keys_action_firstkey (KEY_GENERIC_NEXT_WEEK), - keys_action_firstkey (KEY_GENERIC_GOTO_TODAY), - keys_action_firstkey (KEY_GENERIC_SCROLL_UP), - keys_action_firstkey (KEY_GENERIC_SCROLL_DOWN)); + snprintf(hscr[HELP_GENERAL].text, HELPTEXTSIZ, + _ + ("Some of the keybindings apply whatever panel is selected. They are\n" + "called generic keybinding.\n" + "Here is the list of all the generic key bindings, together with their\n" + "corresponding action:\n\n" + " '%s' : Redraw function -> redraws calcurse panels, this is useful if\n" + " you resize your terminal screen or when\n" + " garbage appears inside the display\n" + " '%s' : Add Appointment -> add an appointment or an event\n" + " '%s' : Add ToDo -> add a todo\n" + " '%s' : -1 Day -> move to previous day\n" + " '%s' : +1 Day -> move to next day\n" + " '%s' : -1 Week -> move to previous week\n" + " '%s' : +1 Week -> move to next week\n" + " '%s' : Goto today -> move to current day\n" + "\nThe '%s' and '%s' keys are used to scroll text upward or downward\n" + "when inside specific screens such the help screens for example.\n" + "They are also used when the calendar screen is selected to switch\n" + "between the available views (monthly and weekly calendar views)."), + keys_action_firstkey(KEY_GENERIC_REDRAW), + keys_action_firstkey(KEY_GENERIC_ADD_APPT), + keys_action_firstkey(KEY_GENERIC_ADD_TODO), + keys_action_firstkey(KEY_GENERIC_PREV_DAY), + keys_action_firstkey(KEY_GENERIC_NEXT_DAY), + keys_action_firstkey(KEY_GENERIC_PREV_WEEK), + keys_action_firstkey(KEY_GENERIC_NEXT_WEEK), + keys_action_firstkey(KEY_GENERIC_GOTO_TODAY), + keys_action_firstkey(KEY_GENERIC_SCROLL_UP), + keys_action_firstkey(KEY_GENERIC_SCROLL_DOWN)); hscr[HELP_OTHER].title = _("OtherCmd\n"); - (void)snprintf (hscr[HELP_OTHER].text, HELPTEXTSIZ, - _("Switch between status bar help pages.\n" - "Because the terminal screen is too narrow to display all of the\n" - "available commands, you need to press '%s' to see the next set of\n" - "commands together with their keybindings.\n" - "Once the last status bar page is reached, pressing '%s' another time\n" - "leads you back to the first page."), - keys_action_firstkey (KEY_GENERIC_OTHER_CMD), - keys_action_firstkey (KEY_GENERIC_OTHER_CMD)); + snprintf(hscr[HELP_OTHER].text, HELPTEXTSIZ, + _("Switch between status bar help pages.\n" + "Because the terminal screen is too narrow to display all of the\n" + "available commands, you need to press '%s' to see the next set of\n" + "commands together with their keybindings.\n" + "Once the last status bar page is reached, pressing '%s' another time\n" + "leads you back to the first page."), + keys_action_firstkey(KEY_GENERIC_OTHER_CMD), + keys_action_firstkey(KEY_GENERIC_OTHER_CMD)); hscr[HELP_CREDITS].title = _("Calcurse - text-based organizer"); - (void)snprintf (hscr[HELP_CREDITS].text, HELPTEXTSIZ, - _("\nCopyright (c) 2004-2011 calcurse Development Team\n" - "All rights reserved.\n" - "\n" - "Redistribution and use in source and binary forms, with or without\n" - "modification, are permitted provided that the following conditions\n" - "are met:\n" - "\n" - "\t- Redistributions of source code must retain the above\n" - "\t copyright notice, this list of conditions and the\n" - "\t following disclaimer.\n" - "\n" - "\t- Redistributions in binary form must reproduce the above\n" - "\t copyright notice, this list of conditions and the\n" - "\t following disclaimer in the documentation and/or other\n" - "\t materials provided with the distribution.\n" - "\n\n" - "Send your feedback or comments to : misc@calcurse.org\n" - "Calcurse home page : http://calcurse.org")); - - help_wins_init (&hwin, 0, 0, (notify_bar ()) ? row - 3 : row - 2, col); + snprintf(hscr[HELP_CREDITS].text, HELPTEXTSIZ, + _("\nCopyright (c) 2004-2012 calcurse Development Team\n" + "All rights reserved.\n" + "\n" + "Redistribution and use in source and binary forms, with or without\n" + "modification, are permitted provided that the following conditions\n" + "are met:\n" + "\n" + "\t- Redistributions of source code must retain the above\n" + "\t copyright notice, this list of conditions and the\n" + "\t following disclaimer.\n" + "\n" + "\t- Redistributions in binary form must reproduce the above\n" + "\t copyright notice, this list of conditions and the\n" + "\t following disclaimer in the documentation and/or other\n" + "\t materials provided with the distribution.\n" + "\n\n" + "Send your feedback or comments to : misc@calcurse.org\n" + "Calcurse home page : http://calcurse.org")); + + help_wins_init(&hwin, 0, 0, (notify_bar())? row - 3 : row - 2, col); oldpage = HELP_MAIN; need_resize = 0; /* Display the help screen related to user input. */ - while (ch != KEY_GENERIC_QUIT) - { - erase_window_part (hwin.win.p, 1, hwin.pad.y, col - 2, - hwin.win.h - 2); - - switch (ch) { - case KEY_GENERIC_SCROLL_DOWN: - wins_scrollwin_down (&hwin, 1); - break; - - case KEY_GENERIC_SCROLL_UP: - wins_scrollwin_up (&hwin, 1); - break; - - default: - page = wanted_page (ch); - if (page != NOPAGE) { - hwin.first_visible_line = 0; - hwin.total_lines = help_write_pad (&hwin.pad, hscr[page].title, - hscr[page].text, ch); - oldpage = page; - } + while (ch != KEY_GENERIC_QUIT) { + erase_window_part(hwin.win.p, 1, hwin.pad.y, col - 2, hwin.win.h - 2); + + switch (ch) { + case KEY_GENERIC_SCROLL_DOWN: + wins_scrollwin_down(&hwin, 1); + break; + + case KEY_GENERIC_SCROLL_UP: + wins_scrollwin_up(&hwin, 1); + break; + + default: + page = wanted_page(ch); + if (page != NOPAGE) { + hwin.first_visible_line = 0; + hwin.total_lines = help_write_pad(&hwin.pad, hscr[page].title, + hscr[page].text, ch); + oldpage = page; } + } - if (resize) - { - resize = 0; - wins_get_config (); - help_wins_reset (&hwin); - hwin.first_visible_line = 0; - hwin.total_lines = help_write_pad (&hwin.pad, hscr[oldpage].title, - hscr[oldpage].text, ch); - need_resize = 1; - } - - wins_scrollwin_display (&hwin); - ch = keys_getch (win[STA].p); + if (resize) { + resize = 0; + wins_get_config(); + help_wins_reset(&hwin); + hwin.first_visible_line = 0; + hwin.total_lines = help_write_pad(&hwin.pad, hscr[oldpage].title, + hscr[oldpage].text, ch); + need_resize = 1; } - wins_scrollwin_delete (&hwin); + + wins_scrollwin_display(&hwin); + ch = keys_getch(win[STA].p, NULL); + } + wins_scrollwin_delete(&hwin); if (need_resize) - wins_reset (); + wins_reset(); } diff --git a/src/htable.h b/src/htable.h index 10d04c1..3bde5ef 100644 --- a/src/htable.h +++ b/src/htable.h @@ -1,5 +1,5 @@ /* - * 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 @@ -69,9 +69,7 @@ struct name { \ } #define HTABLE_ENTRY(type) \ -struct { \ - struct type *next; /* To build the bucket chain list. */ \ -} +struct type *next /* To build the bucket chain list. */ #define HTABLE_SIZE(head) \ (sizeof (*(head)->bkts) ? sizeof ((head)->bkts) / sizeof (*(head)->bkts) : 0) @@ -106,7 +104,11 @@ struct { \ #define HTABLE_PROTOTYPE(name, type) \ struct type *name##_HTABLE_INSERT(struct name *, struct type *); \ struct type *name##_HTABLE_REMOVE(struct name *, struct type *); \ -struct type *name##_HTABLE_LOOKUP(struct name *, struct type *); +struct type *name##_HTABLE_LOOKUP(struct name *, struct type *); \ +uint32_t name##_HTABLE_FIND_BKT(struct name *, struct type *); \ +int name##_HTABLE_CHAIN_LEN(struct name *, uint32_t); \ +struct type *name##_HTABLE_FIRST_FROM(struct name *, int); \ +struct type *name##_HTABLE_NEXT(struct name *, struct type *); /* * Generate function bodies. @@ -116,7 +118,7 @@ uint32_t \ name##_HTABLE_FIND_BKT(struct name *head, struct type *elm) \ { \ uint32_t __bkt; \ - char *__key; \ + const char *__key; \ int __len; \ \ (key) (elm, &__key, &__len); \ diff --git a/src/ical.c b/src/ical.c new file mode 100644 index 0000000..ca10865 --- /dev/null +++ b/src/ical.c @@ -0,0 +1,1090 @@ +/* + * 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 <sys/types.h> + +#include "calcurse.h" + +#define ICALDATEFMT "%Y%m%d" +#define ICALDATETIMEFMT "%Y%m%dT%H%M%S" + +typedef enum { + ICAL_VEVENT, + ICAL_VTODO, + ICAL_TYPES +} ical_types_e; + +typedef enum { + UNDEFINED, + APPOINTMENT, + EVENT +} ical_vevent_e; + +typedef struct { + enum recur_type type; + int freq; + long until; + unsigned count; +} ical_rpt_t; + +static void ical_export_header(FILE *); +static void ical_export_recur_events(FILE *); +static void ical_export_events(FILE *); +static void ical_export_recur_apoints(FILE *); +static void ical_export_apoints(FILE *); +static void ical_export_todo(FILE *); +static void ical_export_footer(FILE *); + +static const char *ical_recur_type[RECUR_TYPES] = + { "", "DAILY", "WEEKLY", "MONTHLY", "YEARLY" }; + +/* iCal alarm notification. */ +static void ical_export_valarm(FILE * stream) +{ + fputs("BEGIN:VALARM\n", stream); + pthread_mutex_lock(&nbar.mutex); + fprintf(stream, "TRIGGER:-P%dS\n", nbar.cntdwn); + pthread_mutex_unlock(&nbar.mutex); + fputs("ACTION:DISPLAY\n", stream); + fputs("END:VALARM\n", stream); +} + +/* Export header. */ +static void ical_export_header(FILE * stream) +{ + fputs("BEGIN:VCALENDAR\n", stream); + fprintf(stream, "PRODID:-//calcurse//NONSGML v%s//EN\n", VERSION); + fputs("VERSION:2.0\n", stream); +} + +/* Export footer. */ +static void ical_export_footer(FILE * stream) +{ + fputs("END:VCALENDAR\n", stream); +} + +/* Export recurrent events. */ +static void ical_export_recur_events(FILE * stream) +{ + llist_item_t *i, *j; + char ical_date[BUFSIZ]; + + LLIST_FOREACH(&recur_elist, i) { + struct recur_event *rev = LLIST_GET_DATA(i); + date_sec2date_fmt(rev->day, ICALDATEFMT, ical_date); + fputs("BEGIN:VEVENT\n", stream); + fprintf(stream, "DTSTART:%s\n", ical_date); + fprintf(stream, "RRULE:FREQ=%s;INTERVAL=%d", + ical_recur_type[rev->rpt->type], rev->rpt->freq); + + if (rev->rpt->until != 0) { + date_sec2date_fmt(rev->rpt->until, ICALDATEFMT, ical_date); + fprintf(stream, ";UNTIL=%s\n", ical_date); + } else + fputc('\n', stream); + + if (LLIST_FIRST(&rev->exc)) { + fputs("EXDATE:", stream); + LLIST_FOREACH(&rev->exc, j) { + struct excp *exc = LLIST_GET_DATA(j); + date_sec2date_fmt(exc->st, ICALDATEFMT, ical_date); + fprintf(stream, "%s", ical_date); + if (LLIST_NEXT(j)) + fputc(',', stream); + else + fputc('\n', stream); + } + } + + fprintf(stream, "SUMMARY:%s\n", rev->mesg); + fputs("END:VEVENT\n", stream); + } +} + +/* Export events. */ +static void ical_export_events(FILE * stream) +{ + llist_item_t *i; + char ical_date[BUFSIZ]; + + LLIST_FOREACH(&eventlist, i) { + struct event *ev = LLIST_TS_GET_DATA(i); + date_sec2date_fmt(ev->day, ICALDATEFMT, ical_date); + fputs("BEGIN:VEVENT\n", stream); + fprintf(stream, "DTSTART:%s\n", ical_date); + fprintf(stream, "SUMMARY:%s\n", ev->mesg); + fputs("END:VEVENT\n", stream); + } +} + +/* Export recurrent appointments. */ +static void ical_export_recur_apoints(FILE * stream) +{ + llist_item_t *i, *j; + char ical_datetime[BUFSIZ]; + char ical_date[BUFSIZ]; + + LLIST_TS_LOCK(&recur_alist_p); + LLIST_TS_FOREACH(&recur_alist_p, i) { + struct recur_apoint *rapt = LLIST_TS_GET_DATA(i); + + date_sec2date_fmt(rapt->start, ICALDATETIMEFMT, ical_datetime); + fputs("BEGIN:VEVENT\n", stream); + fprintf(stream, "DTSTART:%s\n", ical_datetime); + fprintf(stream, "DURATION:PT0H0M%ldS\n", rapt->dur); + fprintf(stream, "RRULE:FREQ=%s;INTERVAL=%d", + ical_recur_type[rapt->rpt->type], rapt->rpt->freq); + + if (rapt->rpt->until != 0) { + date_sec2date_fmt(rapt->rpt->until + HOURINSEC, ICALDATEFMT, ical_date); + fprintf(stream, ";UNTIL=%s\n", ical_date); + } else + fputc('\n', stream); + + if (LLIST_FIRST(&rapt->exc)) { + fputs("EXDATE:", stream); + LLIST_FOREACH(&rapt->exc, j) { + struct excp *exc = LLIST_GET_DATA(j); + date_sec2date_fmt(exc->st, ICALDATEFMT, ical_date); + fprintf(stream, "%s", ical_date); + if (LLIST_NEXT(j)) + fputc(',', stream); + else + fputc('\n', stream); + } + } + + fprintf(stream, "SUMMARY:%s\n", rapt->mesg); + if (rapt->state & APOINT_NOTIFY) + ical_export_valarm(stream); + fputs("END:VEVENT\n", stream); + } + LLIST_TS_UNLOCK(&recur_alist_p); +} + +/* Export appointments. */ +static void ical_export_apoints(FILE * stream) +{ + llist_item_t *i; + char ical_datetime[BUFSIZ]; + + LLIST_TS_LOCK(&alist_p); + LLIST_TS_FOREACH(&alist_p, i) { + struct apoint *apt = LLIST_TS_GET_DATA(i); + date_sec2date_fmt(apt->start, ICALDATETIMEFMT, ical_datetime); + fputs("BEGIN:VEVENT\n", stream); + fprintf(stream, "DTSTART:%s\n", ical_datetime); + fprintf(stream, "DURATION:P%ldDT%ldH%ldM%ldS\n", + apt->dur / DAYINSEC, + (apt->dur / HOURINSEC) % DAYINHOURS, + (apt->dur / MININSEC) % HOURINMIN, apt->dur % MININSEC); + fprintf(stream, "SUMMARY:%s\n", apt->mesg); + if (apt->state & APOINT_NOTIFY) + ical_export_valarm(stream); + fputs("END:VEVENT\n", stream); + } + LLIST_TS_UNLOCK(&alist_p); +} + +/* Export todo items. */ +static void ical_export_todo(FILE * stream) +{ + llist_item_t *i; + + LLIST_FOREACH(&todolist, i) { + struct todo *todo = LLIST_TS_GET_DATA(i); + if (todo->id < 0) /* completed items */ + continue; + + fputs("BEGIN:VTODO\n", stream); + fprintf(stream, "PRIORITY:%d\n", todo->id); + fprintf(stream, "SUMMARY:%s\n", todo->mesg); + fputs("END:VTODO\n", stream); + } +} + +/* Print a header to describe import log report format. */ +static void ical_log_init(FILE * log, float version) +{ + const char *header = + "+-------------------------------------------------------------------+\n" + "| Calcurse icalendar import log. |\n" + "| |\n" + "| Items imported from icalendar file, version %1.1f |\n" + "| Some items could not be imported, they are described hereafter. |\n" + "| The log line format is as follows: |\n" + "| |\n" + "| TYPE [LINE]: DESCRIPTION |\n" + "| |\n" + "| where: |\n" + "| * TYPE represents the item type ('VEVENT' or 'VTODO') |\n" + "| * LINE is the line in the input stream at which this item begins |\n" + "| * DESCRIPTION indicates why the item could not be imported |\n" + "+-------------------------------------------------------------------+\n\n"; + + if (log) + fprintf(log, header, version); +} + +/* + * Used to build a report of the import process. + * The icalendar item for which a problem occurs is mentioned (by giving its + * first line inside the icalendar file), together with a message describing the + * problem. + */ +static void ical_log(FILE * log, ical_types_e type, unsigned lineno, char *msg) +{ + const char *typestr[ICAL_TYPES] = { "VEVENT", "VTODO" }; + + RETURN_IF(type < 0 || type >= ICAL_TYPES, _("unknown ical type")); + if (log) + fprintf(log, "%s [%d]: %s\n", typestr[type], lineno, msg); +} + +static void ical_store_todo(int priority, char *mesg, char *note) +{ + todo_add(mesg, priority, note); + mem_free(mesg); + erase_note(¬e); +} + +static void +ical_store_event(char *mesg, char *note, long day, long end, ical_rpt_t * rpt, + llist_t * exc) +{ + const int EVENTID = 1; + + if (rpt) { + recur_event_new(mesg, note, day, EVENTID, rpt->type, rpt->freq, + rpt->until, exc); + mem_free(rpt); + } else if (end && end != day) { + /* Here we have an event that spans over several days. */ + rpt = mem_malloc(sizeof(ical_rpt_t)); + rpt->type = RECUR_DAILY; + rpt->freq = 1; + rpt->count = 0; + rpt->until = end; + recur_event_new(mesg, note, day, EVENTID, rpt->type, rpt->freq, + rpt->until, exc); + mem_free(rpt); + } else { + event_new(mesg, note, day, EVENTID); + } + mem_free(mesg); + erase_note(¬e); +} + +static void +ical_store_apoint(char *mesg, char *note, long start, long dur, + ical_rpt_t * rpt, llist_t * exc, int has_alarm) +{ + char state = 0L; + + if (has_alarm) + state |= APOINT_NOTIFY; + if (rpt) { + recur_apoint_new(mesg, note, start, dur, state, rpt->type, rpt->freq, + rpt->until, exc); + mem_free(rpt); + } else { + apoint_new(mesg, note, start, dur, state); + } + mem_free(mesg); + erase_note(¬e); +} + +/* + * Returns an allocated string representing the string given in argument once + * unformatted. + * + * Note: + * Even if the RFC2445 recommends not to have more than 75 octets on one line of + * text, I prefer not to restrict the parsing to this size, thus I use a buffer + * of size BUFSIZ. + * + * Extract from RFC2445: + * Lines of text SHOULD NOT be longer than 75 octets, excluding the line + * break. + */ +static char *ical_unformat_line(char *line) +{ + char *p, uline[BUFSIZ]; + int len; + + if (strlen(line) >= BUFSIZ) + return NULL; + + memset(uline, 0, BUFSIZ); + for (len = 0, p = line; *p; p++) { + switch (*p) { + case '\\': + switch (*(p + 1)) { + case 'n': + uline[len++] = '\n'; + p++; + break; + case 't': + uline[len++] = '\t'; + p++; + break; + case ';': + case ':': + case ',': + uline[len++] = *(p + 1); + p++; + break; + default: + uline[len++] = *p; + break; + } + break; + default: + uline[len++] = *p; + break; + } + } + + return mem_strdup(uline); +} + +static void +ical_readline_init(FILE * fdi, char *buf, char *lstore, unsigned *ln) +{ + char *eol; + + *buf = *lstore = '\0'; + if (fgets(lstore, BUFSIZ, fdi)) { + if ((eol = strchr(lstore, '\n')) != NULL) + *eol = '\0'; + (*ln)++; + } +} + +static int ical_readline(FILE * fdi, char *buf, char *lstore, unsigned *ln) +{ + char *eol; + + strncpy(buf, lstore, BUFSIZ); + (*ln)++; + + while (fgets(lstore, BUFSIZ, fdi) != NULL) { + if ((eol = strchr(lstore, '\n')) != NULL) + *eol = '\0'; + if (*lstore != SPACE && *lstore != TAB) + break; + strncat(buf, lstore + 1, BUFSIZ - strlen(buf) - 1); + (*ln)++; + } + + if (feof(fdi)) { + *lstore = '\0'; + if (*buf == '\0') + return 0; + } + + return 1; +} + +static float +ical_chk_header(FILE * fd, char *buf, char *lstore, unsigned *lineno) +{ + const int HEADER_MALFORMED = -1; + const char icalheader[] = "BEGIN:VCALENDAR"; + float version; + + if (!ical_readline(fd, buf, lstore, lineno)) + return HEADER_MALFORMED; + + str_toupper(buf); + if (strncmp(buf, icalheader, sizeof(icalheader) - 1) != 0) + return HEADER_MALFORMED; + + while (!sscanf(buf, "VERSION:%f", &version)) { + if (!ical_readline(fd, buf, lstore, lineno)) + return HEADER_MALFORMED; + } + return version; +} + +/* + * iCalendar date-time format is based on the ISO 8601 complete + * representation. It should be something like : DATE 'T' TIME + * where DATE is 'YYYYMMDD' and TIME is 'HHMMSS'. + * The time and 'T' separator are optional (in the case of an day-long event). + * + * Optionnaly, if the type pointer is given, specify if it is an event + * (no time is given, meaning it is an all-day event), or an appointment + * (time is given). + * + * The timezone is not yet handled by calcurse. + */ +static long ical_datetime2long(char *datestr, ical_vevent_e * type) +{ + const int NOTFOUND = 0, FORMAT_DATE = 3, FORMAT_DATETIME = 5; + struct date date; + unsigned hour, min; + long datelong; + int format; + + format = sscanf(datestr, "%04u%02u%02uT%02u%02u", + &date.yyyy, &date.mm, &date.dd, &hour, &min); + if (format == FORMAT_DATE) { + if (type) + *type = EVENT; + datelong = date2sec(date, 0, 0); + } else if (format == FORMAT_DATETIME) { + if (type) + *type = APPOINTMENT; + datelong = date2sec(date, hour, min); + } else { + datelong = NOTFOUND; + } + return datelong; +} + +static long ical_durtime2long(char *timestr) +{ + long timelong; + char *p; + + if ((p = strchr(timestr, 'T')) == NULL) + timelong = 0; + else { + int nbmatch; + struct { + unsigned hour, min, sec; + } time; + + p++; + memset(&time, 0, sizeof time); + nbmatch = sscanf(p, "%uH%uM%uS", &time.hour, &time.min, &time.sec); + if (nbmatch < 1 || nbmatch > 3) + timelong = 0; + else + timelong = time.hour * HOURINSEC + time.min * MININSEC + time.sec; + } + return timelong; +} + +/* + * Extract from RFC2445: + * + * Value Name: DURATION + * + * Purpose: This value type is used to identify properties that contain + * duration of time. + * + * Formal Definition: The value type is defined by the following + * notation: + * + * dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week) + * dur-date = dur-day [dur-time] + * dur-time = "T" (dur-hour / dur-minute / dur-second) + * dur-week = 1*DIGIT "W" + * dur-hour = 1*DIGIT "H" [dur-minute] + * dur-minute = 1*DIGIT "M" [dur-second] + * dur-second = 1*DIGIT "S" + * dur-day = 1*DIGIT "D" + * + * Example: A duration of 15 days, 5 hours and 20 seconds would be: + * P15DT5H0M20S + * A duration of 7 weeks would be: + * P7W + */ +static long ical_dur2long(char *durstr) +{ + const int NOTFOUND = -1; + long durlong; + char *p; + struct { + unsigned week, day; + } date; + + memset(&date, 0, sizeof date); + if ((p = strchr(durstr, 'P')) == NULL) + durlong = NOTFOUND; + else { + p++; + if (*p == '-') + return NOTFOUND; + else if (*p == '+') + p++; + + if (*p == 'T') /* dur-time */ + durlong = ical_durtime2long(p); + else if (strchr(p, 'W')) { /* dur-week */ + if (sscanf(p, "%u", &date.week) == 1) + durlong = date.week * WEEKINDAYS * DAYINSEC; + else + durlong = NOTFOUND; + } else { + if (strchr(p, 'D')) { /* dur-date */ + if (sscanf(p, "%uD", &date.day) == 1) { + durlong = date.day * DAYINSEC; + durlong += ical_durtime2long(p); + } else + durlong = NOTFOUND; + } else + durlong = NOTFOUND; + } + } + return durlong; +} + +/* + * Compute the vevent repetition end date from the repetition count. + * + * Extract from RFC2445: + * The COUNT rule part defines the number of occurrences at which to + * range-bound the recurrence. The "DTSTART" property value, if specified, + * counts as the first occurrence. + */ +static long ical_compute_rpt_until(long start, ical_rpt_t * rpt) +{ + long until; + + switch (rpt->type) { + case RECUR_DAILY: + until = date_sec_change(start, 0, rpt->freq * (rpt->count - 1)); + break; + case RECUR_WEEKLY: + until = date_sec_change(start, 0, + rpt->freq * WEEKINDAYS * (rpt->count - 1)); + break; + case RECUR_MONTHLY: + until = date_sec_change(start, rpt->freq * (rpt->count - 1), 0); + break; + case RECUR_YEARLY: + until = date_sec_change(start, rpt->freq * 12 * (rpt->count - 1), 0); + break; + default: + until = 0; + break; + /* NOTREACHED */ + } + return until; +} + +/* + * Read a recurrence rule from an iCalendar RRULE string. + * + * Value Name: RECUR + * + * Purpose: This value type is used to identify properties that contain + * a recurrence rule specification. + * + * Formal Definition: The value type is defined by the following + * notation: + * + * recur = "FREQ"=freq *( + * + * ; either UNTIL or COUNT may appear in a 'recur', + * ; but UNTIL and COUNT MUST NOT occur in the same 'recur' + * + * ( ";" "UNTIL" "=" enddate ) / + * ( ";" "COUNT" "=" 1*DIGIT ) / + * + * ; the rest of these keywords are optional, + * ; but MUST NOT occur more than + * ; once + * + * ( ";" "INTERVAL" "=" 1*DIGIT ) / + * ( ";" "BYSECOND" "=" byseclist ) / + * ( ";" "BYMINUTE" "=" byminlist ) / + * ( ";" "BYHOUR" "=" byhrlist ) / + * ( ";" "BYDAY" "=" bywdaylist ) / + * ( ";" "BYMONTHDAY" "=" bymodaylist ) / + * ( ";" "BYYEARDAY" "=" byyrdaylist ) / + * ( ";" "BYWEEKNO" "=" bywknolist ) / + * ( ";" "BYMONTH" "=" bymolist ) / + * ( ";" "BYSETPOS" "=" bysplist ) / + * ( ";" "WKST" "=" weekday ) / + * ( ";" x-name "=" text ) + * ) +*/ +static ical_rpt_t *ical_read_rrule(FILE * log, char *rrulestr, + unsigned *noskipped, const int itemline) +{ + const char daily[] = "DAILY"; + const char weekly[] = "WEEKLY"; + const char monthly[] = "MONTHLY"; + const char yearly[] = "YEARLY"; + const char count[] = "COUNT="; + const char interv[] = "INTERVAL="; + unsigned interval; + ical_rpt_t *rpt; + char *p; + + rpt = NULL; + if ((p = strchr(rrulestr, ':')) != NULL) { + char freqstr[BUFSIZ]; + + p++; + rpt = mem_malloc(sizeof(ical_rpt_t)); + memset(rpt, 0, sizeof(ical_rpt_t)); + if (sscanf(p, "FREQ=%s", freqstr) != 1) { + ical_log(log, ICAL_VEVENT, itemline, + _("recurrence frequence not found.")); + (*noskipped)++; + mem_free(rpt); + return NULL; + } else { + if (strncmp(freqstr, daily, sizeof(daily) - 1) == 0) + rpt->type = RECUR_DAILY; + else if (strncmp(freqstr, weekly, sizeof(weekly) - 1) == 0) + rpt->type = RECUR_WEEKLY; + else if (strncmp(freqstr, monthly, sizeof(monthly) - 1) == 0) + rpt->type = RECUR_MONTHLY; + else if (strncmp(freqstr, yearly, sizeof(yearly) - 1) == 0) + rpt->type = RECUR_YEARLY; + else { + ical_log(log, ICAL_VEVENT, itemline, + _("recurrence frequence not recognized.")); + (*noskipped)++; + mem_free(rpt); + return NULL; + } + } + /* + The UNTIL rule part defines a date-time value which bounds the + recurrence rule in an inclusive manner. If not present, and the + COUNT rule part is also not present, the RRULE is considered to + repeat forever. + + The COUNT rule part defines the number of occurrences at which to + range-bound the recurrence. The "DTSTART" property value, if + specified, counts as the first occurrence. + */ + if ((p = strstr(rrulestr, "UNTIL")) != NULL) { + char *untilstr; + + untilstr = strchr(p, '='); + rpt->until = ical_datetime2long(++untilstr, NULL); + } else { + unsigned cnt; + char *countstr; + + if ((countstr = strstr(rrulestr, count)) != NULL) { + countstr += sizeof(count) - 1; + if (sscanf(countstr, "%u", &cnt) != 1) { + rpt->until = 0; + /* endless repetition */ + } else { + rpt->count = cnt; + } + } else + rpt->until = 0; + } + + if ((p = strstr(rrulestr, interv)) != NULL) { + p += sizeof(interv) - 1; + if (sscanf(p, "%u", &interval) != 1) { + rpt->freq = 1; + /* default frequence if none specified */ + } else { + rpt->freq = interval; + } + } else { + rpt->freq = 1; + } + } else { + ical_log(log, ICAL_VEVENT, itemline, _("recurrence rule malformed.")); + (*noskipped)++; + } + return rpt; +} + +static void ical_add_exc(llist_t * exc_head, long date) +{ + if (date != 0) { + struct excp *exc = mem_malloc(sizeof(struct excp)); + exc->st = date; + + LLIST_ADD(exc_head, exc); + } +} + +/* + * This property defines the list of date/time exceptions for a + * recurring calendar component. + */ +static void +ical_read_exdate(llist_t * exc, FILE * log, char *exstr, unsigned *noskipped, + const int itemline) +{ + char *p, *q; + long date; + + LLIST_INIT(exc); + if ((p = strchr(exstr, ':')) != NULL) { + p++; + while ((q = strchr(p, ',')) != NULL) { + char buf[BUFSIZ]; + const int buflen = q - p; + + strncpy(buf, p, buflen); + buf[buflen] = '\0'; + date = ical_datetime2long(buf, NULL); + ical_add_exc(exc, date); + p = ++q; + } + date = ical_datetime2long(p, NULL); + ical_add_exc(exc, date); + } else { + ical_log(log, ICAL_VEVENT, itemline, + _("recurrence exception dates malformed.")); + (*noskipped)++; + } +} + +/* Return an allocated string containing the name of the newly created note. */ +static char *ical_read_note(char *line, unsigned *noskipped, + ical_vevent_e item_type, const int itemline, + FILE * log) +{ + char *p, *notestr, *note; + + if ((p = strchr(line, ':')) != NULL) { + p++; + notestr = ical_unformat_line(p); + if (notestr == NULL) { + ical_log(log, item_type, itemline, + _("could not get entire item description.")); + (*noskipped)++; + return NULL; + } else if (strlen(notestr) == 0) { + mem_free(notestr); + return NULL; + } else { + note = generate_note(notestr); + mem_free(notestr); + return note; + } + } else { + ical_log(log, item_type, itemline, _("description malformed.")); + (*noskipped)++; + return NULL; + } +} + +/* Returns an allocated string containing the ical item summary. */ +static char *ical_read_summary(char *line) +{ + char *p, *summary; + + if ((p = strchr(line, ':')) != NULL) { + p++; + summary = ical_unformat_line(p); + return summary; + } else + return NULL; +} + +static void +ical_read_event(FILE * fdi, FILE * log, unsigned *noevents, unsigned *noapoints, + unsigned *noskipped, char *buf, char *lstore, unsigned *lineno) +{ + const int ITEMLINE = *lineno; + const char endevent[] = "END:VEVENT"; + const char summary[] = "SUMMARY"; + const char dtstart[] = "DTSTART"; + const char dtend[] = "DTEND"; + const char duration[] = "DURATION"; + const char rrule[] = "RRULE"; + const char exdate[] = "EXDATE"; + const char alarm[] = "BEGIN:VALARM"; + const char endalarm[] = "END:VALARM"; + const char desc[] = "DESCRIPTION"; + ical_vevent_e vevent_type; + char *p, buf_upper[BUFSIZ]; + struct { + llist_t exc; + ical_rpt_t *rpt; + char *mesg, *note; + long start, end, dur; + int has_alarm; + } vevent; + int skip_alarm; + + vevent_type = UNDEFINED; + memset(&vevent, 0, sizeof vevent); + skip_alarm = 0; + while (ical_readline(fdi, buf, lstore, lineno)) { + strncpy(buf_upper, buf, BUFSIZ); + buf_upper[BUFSIZ - 1] = '\0'; + str_toupper(buf_upper); + + if (skip_alarm) { + /* Need to skip VALARM properties because some keywords could + interfere, such as DURATION, SUMMARY,.. */ + if (strncmp(buf_upper, endalarm, sizeof(endalarm) - 1) == 0) + skip_alarm = 0; + continue; + } + if (strncmp(buf_upper, endevent, sizeof(endevent) - 1) == 0) { + if (vevent.mesg) { + if (vevent.rpt && vevent.rpt->count) + vevent.rpt->until = ical_compute_rpt_until(vevent.start, vevent.rpt); + + switch (vevent_type) { + case APPOINTMENT: + if (vevent.start == 0) { + ical_log(log, ICAL_VEVENT, ITEMLINE, + _("appointment has no start time.")); + goto cleanup; + } + if (vevent.dur == 0) { + if (vevent.end == 0) { + ical_log(log, ICAL_VEVENT, ITEMLINE, + _("could not compute duration " "(no end time).")); + goto cleanup; + } else if (vevent.start == vevent.end) { + vevent_type = EVENT; + vevent.end = 0L; + ical_store_event(vevent.mesg, vevent.note, + vevent.start, vevent.end, + vevent.rpt, &vevent.exc); + (*noevents)++; + return; + } else { + vevent.dur = vevent.end - vevent.start; + if (vevent.dur < 0) { + ical_log(log, ICAL_VEVENT, ITEMLINE, + _("item has a negative duration.")); + goto cleanup; + } + } + } + ical_store_apoint(vevent.mesg, vevent.note, vevent.start, + vevent.dur, vevent.rpt, &vevent.exc, + vevent.has_alarm); + (*noapoints)++; + break; + case EVENT: + if (vevent.start == 0) { + ical_log(log, ICAL_VEVENT, ITEMLINE, + _("event date is not defined.")); + goto cleanup; + } + ical_store_event(vevent.mesg, vevent.note, vevent.start, + vevent.end, vevent.rpt, &vevent.exc); + (*noevents)++; + break; + case UNDEFINED: + ical_log(log, ICAL_VEVENT, ITEMLINE, + _("item could not be identified.")); + goto cleanup; + break; + } + } else { + ical_log(log, ICAL_VEVENT, ITEMLINE, + _("could not retrieve item summary.")); + goto cleanup; + } + return; + } else { + if (strncmp(buf_upper, dtstart, sizeof(dtstart) - 1) == 0) { + if ((p = strchr(buf, ':')) != NULL) + vevent.start = ical_datetime2long(++p, &vevent_type); + if (!vevent.start) { + ical_log(log, ICAL_VEVENT, ITEMLINE, + _("could not retrieve event start time.")); + goto cleanup; + } + } else if (strncmp(buf_upper, dtend, sizeof(dtend) - 1) == 0) { + if ((p = strchr(buf, ':')) != NULL) + vevent.end = ical_datetime2long(++p, &vevent_type); + if (!vevent.end) { + ical_log(log, ICAL_VEVENT, ITEMLINE, + _("could not retrieve event end time.")); + goto cleanup; + } + } else if (strncmp(buf_upper, duration, sizeof(duration) - 1) == 0) { + if ((vevent.dur = ical_dur2long(buf)) <= 0) { + ical_log(log, ICAL_VEVENT, ITEMLINE, _("item duration malformed.")); + goto cleanup; + } + } else if (strncmp(buf_upper, rrule, sizeof(rrule) - 1) == 0) { + vevent.rpt = ical_read_rrule(log, buf, noskipped, ITEMLINE); + } else if (strncmp(buf_upper, exdate, sizeof(exdate) - 1) == 0) { + ical_read_exdate(&vevent.exc, log, buf, noskipped, ITEMLINE); + } else if (strncmp(buf_upper, summary, sizeof(summary) - 1) == 0) { + vevent.mesg = ical_read_summary(buf); + } else if (strncmp(buf_upper, alarm, sizeof(alarm) - 1) == 0) { + skip_alarm = 1; + vevent.has_alarm = 1; + } else if (strncmp(buf_upper, desc, sizeof(desc) - 1) == 0) { + vevent.note = ical_read_note(buf, noskipped, ICAL_VEVENT, + ITEMLINE, log); + } + } + } + ical_log(log, ICAL_VEVENT, ITEMLINE, + _("The ical file seems to be malformed. " + "The end of item was not found.")); + +cleanup: + + if (vevent.note) + mem_free(vevent.note); + if (vevent.mesg) + mem_free(vevent.mesg); + if (vevent.rpt) + mem_free(vevent.rpt); + LLIST_FREE(&vevent.exc); + (*noskipped)++; +} + +static void +ical_read_todo(FILE * fdi, FILE * log, unsigned *notodos, unsigned *noskipped, + char *buf, char *lstore, unsigned *lineno) +{ + const char endtodo[] = "END:VTODO"; + const char summary[] = "SUMMARY"; + const char alarm[] = "BEGIN:VALARM"; + const char endalarm[] = "END:VALARM"; + const char desc[] = "DESCRIPTION"; + const int LOWEST = 9; + const int ITEMLINE = *lineno; + char buf_upper[BUFSIZ]; + struct { + char *mesg, *note; + int has_priority, priority; + } vtodo; + int skip_alarm; + + memset(&vtodo, 0, sizeof vtodo); + skip_alarm = 0; + while (ical_readline(fdi, buf, lstore, lineno)) { + strncpy(buf_upper, buf, BUFSIZ); + buf_upper[BUFSIZ - 1] = '\0'; + str_toupper(buf_upper); + if (skip_alarm) { + /* Need to skip VALARM properties because some keywords could + interfere, such as DURATION, SUMMARY,.. */ + if (strncmp(buf_upper, endalarm, sizeof(endalarm) - 1) == 0) + skip_alarm = 0; + continue; + } + if (strncmp(buf_upper, endtodo, sizeof(endtodo) - 1) == 0) { + if (!vtodo.has_priority) + vtodo.priority = LOWEST; + if (vtodo.mesg) { + ical_store_todo(vtodo.priority, vtodo.mesg, vtodo.note); + (*notodos)++; + } else { + ical_log(log, ICAL_VTODO, ITEMLINE, + _("could not retrieve item summary.")); + goto cleanup; + } + return; + } else { + int tmpint; + + if (sscanf(buf_upper, "PRIORITY:%d", &tmpint) == 1) { + if (tmpint <= 9 && tmpint >= 1) { + vtodo.priority = tmpint; + vtodo.has_priority = 1; + } else { + ical_log(log, ICAL_VTODO, ITEMLINE, + _("item priority is not acceptable " + "(must be between 1 and 9).")); + vtodo.priority = LOWEST; + } + } else if (strncmp(buf_upper, summary, sizeof(summary) - 1) == 0) { + vtodo.mesg = ical_read_summary(buf); + } else if (strncmp(buf_upper, alarm, sizeof(alarm) - 1) == 0) { + skip_alarm = 1; + } else if (strncmp(buf_upper, desc, sizeof(desc) - 1) == 0) { + vtodo.note = ical_read_note(buf, noskipped, ICAL_VTODO, ITEMLINE, log); + } + } + } + ical_log(log, ICAL_VTODO, ITEMLINE, + _("The ical file seems to be malformed. " + "The end of item was not found.")); + +cleanup: + + if (vtodo.note) + mem_free(vtodo.note); + if (vtodo.mesg) + mem_free(vtodo.mesg); + (*noskipped)++; +} + +/* Import calcurse data. */ +void +ical_import_data(FILE * stream, FILE * log, unsigned *events, unsigned *apoints, + unsigned *todos, unsigned *lines, unsigned *skipped) +{ + const char vevent[] = "BEGIN:VEVENT"; + const char vtodo[] = "BEGIN:VTODO"; + char buf[BUFSIZ], lstore[BUFSIZ]; + float ical_version; + + ical_readline_init(stream, buf, lstore, lines); + ical_version = ical_chk_header(stream, buf, lstore, lines); + RETURN_IF(ical_version < 0, + _("Warning: ical header malformed or wrong version number. " + "Aborting...")); + + ical_log_init(log, ical_version); + + while (ical_readline(stream, buf, lstore, lines)) { + (*lines)++; + str_toupper(buf); + if (strncmp(buf, vevent, sizeof(vevent) - 1) == 0) { + ical_read_event(stream, log, events, apoints, skipped, buf, lstore, + lines); + } else if (strncmp(buf, vtodo, sizeof(vtodo) - 1) == 0) { + ical_read_todo(stream, log, todos, skipped, buf, lstore, lines); + } + } +} + +/* Export calcurse data. */ +void ical_export_data(FILE * stream) +{ + ical_export_header(stream); + ical_export_recur_events(stream); + ical_export_events(stream); + ical_export_recur_apoints(stream); + ical_export_apoints(stream); + ical_export_todo(stream); + ical_export_footer(stream); +} @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -45,9 +45,7 @@ #include <errno.h> #include "calcurse.h" - -#define ICALDATEFMT "%Y%m%d" -#define ICALDATETIMEFMT "%Y%m%dT%H%M%S" +#include "sha1.h" typedef enum { PROGRESS_BAR_SAVE, @@ -68,650 +66,147 @@ enum { PROGRESS_BAR_EXPORT_TODO }; -typedef enum { - ICAL_VEVENT, - ICAL_VTODO, - ICAL_TYPES -} ical_types_e; - -typedef enum { - UNDEFINED, - APPOINTMENT, - EVENT -} ical_vevent_e; - -typedef struct { - enum recur_type type; - int freq; - long until; - unsigned count; -} ical_rpt_t; - struct ht_keybindings_s { - char *label; - enum key key; - HTABLE_ENTRY (ht_keybindings_s); + const char *label; + enum key key; + HTABLE_ENTRY(ht_keybindings_s); }; -/* Type definition for callbacks to multiple-mode export functions. */ -typedef void (*cb_export_t)(FILE *); -typedef void (*cb_dump_t)(FILE *, long, long, char *); - -/* Static functions used to add export functionalities. */ -static void ical_export_header (FILE *); -static void ical_export_recur_events (FILE *); -static void ical_export_events (FILE *); -static void ical_export_recur_apoints (FILE *); -static void ical_export_apoints (FILE *); -static void ical_export_todo (FILE *); -static void ical_export_footer (FILE *); - -static void pcal_export_header (FILE *); -static void pcal_export_recur_events (FILE *); -static void pcal_export_events (FILE *); -static void pcal_export_recur_apoints (FILE *); -static void pcal_export_apoints (FILE *); -static void pcal_export_todo (FILE *); -static void pcal_export_footer (FILE *); - -cb_export_t cb_export_header[IO_EXPORT_NBTYPES] = - {ical_export_header, pcal_export_header}; -cb_export_t cb_export_recur_events[IO_EXPORT_NBTYPES] = - {ical_export_recur_events, pcal_export_recur_events}; -cb_export_t cb_export_events[IO_EXPORT_NBTYPES] = - {ical_export_events, pcal_export_events}; -cb_export_t cb_export_recur_apoints[IO_EXPORT_NBTYPES] = - {ical_export_recur_apoints, pcal_export_recur_apoints}; -cb_export_t cb_export_apoints[IO_EXPORT_NBTYPES] = - {ical_export_apoints, pcal_export_apoints}; -cb_export_t cb_export_todo[IO_EXPORT_NBTYPES] = - {ical_export_todo, pcal_export_todo}; -cb_export_t cb_export_footer[IO_EXPORT_NBTYPES] = - {ical_export_footer, pcal_export_footer}; - -static char *ical_recur_type[RECUR_TYPES] = - { "", "DAILY", "WEEKLY", "MONTHLY", "YEARLY" }; +static void load_keys_ht_getkey(struct ht_keybindings_s *, const char **, + int *); +static int load_keys_ht_compare(struct ht_keybindings_s *, + struct ht_keybindings_s *); + +#define HSIZE 256 +HTABLE_HEAD(ht_keybindings, HSIZE, ht_keybindings_s); +HTABLE_PROTOTYPE(ht_keybindings, ht_keybindings_s) + HTABLE_GENERATE(ht_keybindings, ht_keybindings_s, load_keys_ht_getkey, + load_keys_ht_compare) /* Draw a progress bar while saving, loading or exporting data. */ -static void -progress_bar (progress_bar_t type, int progress) +static void progress_bar(progress_bar_t type, int progress) { -#define SLEEPTIME 125000 #define NBFILES 4 #define NBEXPORTED 3 #define LABELENGTH 15 int i, step, steps; - char *mesg_sav = _("Saving..."); - char *mesg_load = _("Loading..."); - char *mesg_export = _("Exporting..."); - char *error_msg = _("Internal error while displaying progress bar"); - char *barchar = "|"; - char *file[NBFILES] = { + const char *mesg_sav = _("Saving..."); + const char *mesg_load = _("Loading..."); + const char *mesg_export = _("Exporting..."); + const char *error_msg = _("Internal error while displaying progress bar"); + const char *barchar = "|"; + const char *file[NBFILES] = { "[ conf ]", "[ todo ]", "[ apts ]", "[ keys ]" }; - char *data[NBEXPORTED] = { + const char *data[NBEXPORTED] = { "[ events ]", "[appointments]", "[ todo ]" }; - int ipos = LABELENGTH + 2; + int ipos = LABELENGTH + 2; int epos[NBFILES]; /* progress bar length init. */ ipos = LABELENGTH + 2; steps = (type == PROGRESS_BAR_EXPORT) ? NBEXPORTED : NBFILES; - step = floor (col / (steps + 1)); + step = floor(col / (steps + 1)); for (i = 0; i < steps - 1; i++) epos[i] = (i + 2) * step; epos[steps - 1] = col - 2; - switch (type) - { - case PROGRESS_BAR_SAVE: - EXIT_IF (progress < 0 || progress > PROGRESS_BAR_KEYS, "%s", error_msg); - status_mesg (mesg_sav, file[progress]); - break; - case PROGRESS_BAR_LOAD: - EXIT_IF (progress < 0 || progress > PROGRESS_BAR_KEYS, "%s", error_msg); - status_mesg (mesg_load, file[progress]); - break; - case PROGRESS_BAR_EXPORT: - EXIT_IF (progress < 0 - || progress > PROGRESS_BAR_EXPORT_TODO, "%s", error_msg); - status_mesg (mesg_export, data[progress]); - break; - } + switch (type) { + case PROGRESS_BAR_SAVE: + EXIT_IF(progress < 0 || progress > PROGRESS_BAR_KEYS, "%s", error_msg); + status_mesg(mesg_sav, file[progress]); + break; + case PROGRESS_BAR_LOAD: + EXIT_IF(progress < 0 || progress > PROGRESS_BAR_KEYS, "%s", error_msg); + status_mesg(mesg_load, file[progress]); + break; + case PROGRESS_BAR_EXPORT: + EXIT_IF(progress < 0 + || progress > PROGRESS_BAR_EXPORT_TODO, "%s", error_msg); + status_mesg(mesg_export, data[progress]); + break; + } /* Draw the progress bar. */ - mvwprintw (win[STA].p, 1, ipos, barchar); - mvwprintw (win[STA].p, 1, epos[steps - 1], barchar); - custom_apply_attr (win[STA].p, ATTR_HIGHEST); + mvwprintw(win[STA].p, 1, ipos, barchar); + mvwprintw(win[STA].p, 1, epos[steps - 1], barchar); + custom_apply_attr(win[STA].p, ATTR_HIGHEST); for (i = ipos + 1; i < epos[progress]; i++) - mvwaddch (win[STA].p, 1, i, ' ' | A_REVERSE); - custom_remove_attr (win[STA].p, ATTR_HIGHEST); - wmove (win[STA].p, 0, 0); - wins_wrefresh (win[STA].p); - (void)usleep (SLEEPTIME); -#undef SLEEPTIME + mvwaddch(win[STA].p, 1, i, ' ' | A_REVERSE); + custom_remove_attr(win[STA].p, ATTR_HIGHEST); + wmove(win[STA].p, 0, 0); + wins_wrefresh(win[STA].p); #undef NBFILES #undef NBEXPORTED #undef LABELENGTH } /* Ask user for a file name to export data to. */ -static FILE * -get_export_stream (enum export_type type) +static FILE *get_export_stream(enum export_type type) { FILE *stream; int cancel; char *home, *stream_name; - char *question = _("Choose the file used to export calcurse data:"); - char *wrong_name = - _("The file cannot be accessed, please enter another file name."); - char *press_enter = _("Press [ENTER] to continue."); - const char *file_ext[IO_EXPORT_NBTYPES] = {"ical", "txt"}; + const char *question = _("Choose the file used to export calcurse data:"); + const char *wrong_name = + _("The file cannot be accessed, please enter another file name."); + const char *press_enter = _("Press [ENTER] to continue."); + const char *file_ext[IO_EXPORT_NBTYPES] = { "ical", "txt" }; stream = NULL; - stream_name = (char *) mem_malloc (BUFSIZ); - if ((home = getenv ("HOME")) != NULL) - (void)snprintf (stream_name, BUFSIZ, "%s/calcurse.%s", home, - file_ext[type]); + stream_name = (char *)mem_malloc(BUFSIZ); + if ((home = getenv("HOME")) != NULL) + snprintf(stream_name, BUFSIZ, "%s/calcurse.%s", home, file_ext[type]); else - (void)snprintf (stream_name, BUFSIZ, "%s/calcurse.%s", get_tempdir (), - file_ext[type]); - - while (stream == NULL) - { - status_mesg (question, ""); - cancel = updatestring (win[STA].p, &stream_name, 0, 1); - if (cancel) - { - mem_free (stream_name); - return (NULL); - } - stream = fopen (stream_name, "w"); - if (stream == NULL) - { - status_mesg (wrong_name, press_enter); - (void)wgetch (win[STA].p); - } - } - mem_free (stream_name); - - return (stream); -} - -/* - * Travel through each occurence of an item, and execute the given callback - * (mainly used to export data). - */ -static void -foreach_date_dump (const long date_end, struct rpt *rpt, llist_t *exc, - long item_first_date, long item_dur, char *item_mesg, - cb_dump_t cb_dump, FILE *stream) -{ - long date, item_time; - struct tm lt; - time_t t; - - t = item_first_date; - lt = *localtime (&t); - lt.tm_hour = lt.tm_min = lt.tm_sec = 0; - lt.tm_isdst = -1; - date = mktime (<); - item_time = item_first_date - date; - - while (date <= date_end && date <= rpt->until) - { - if (recur_item_inday (item_first_date, exc, rpt->type, rpt->freq, - rpt->until, date)) - { - (*cb_dump)(stream, date + item_time, item_dur, item_mesg); - } - switch (rpt->type) - { - case RECUR_DAILY: - date = date_sec_change (date, 0, rpt->freq); - break; - case RECUR_WEEKLY: - date = date_sec_change (date, 0, rpt->freq * WEEKINDAYS); - break; - case RECUR_MONTHLY: - date = date_sec_change (date, rpt->freq, 0); - break; - case RECUR_YEARLY: - date = date_sec_change (date, rpt->freq * 12, 0); - break; - default: - EXIT (_("incoherent repetition type")); - /* NOTREACHED */ - break; - } - } -} - -/* iCal alarm notification. */ -static void -ical_export_valarm (FILE *stream) -{ - (void)fprintf (stream, "BEGIN:VALARM\n"); - pthread_mutex_lock (&nbar.mutex); - (void)fprintf (stream, "TRIGGER:-P%dS\n", nbar.cntdwn); - pthread_mutex_unlock (&nbar.mutex); - (void)fprintf (stream, "ACTION:DISPLAY\n"); - (void)fprintf (stream, "END:VALARM\n"); -} - -/* Export header. */ -static void -ical_export_header (FILE *stream) -{ - (void)fprintf (stream, "BEGIN:VCALENDAR\n"); - (void)fprintf (stream, "PRODID:-//calcurse//NONSGML v%s//EN\n", VERSION); - (void)fprintf (stream, "VERSION:2.0\n"); -} - -static void -pcal_export_header (FILE *stream) -{ - (void)fprintf (stream, "# calcurse pcal export\n"); - (void)fprintf (stream, "\n# =======\n# options\n# =======\n"); - (void)fprintf (stream, "opt -A -K -l -m -F %s\n", - calendar_week_begins_on_monday () ? - "Monday" : "Sunday"); - (void)fprintf (stream, "# Display week number (i.e. 1-52) on every Monday\n"); - (void)fprintf (stream, "all monday in all week %%w\n"); - (void)fprintf (stream, "\n"); -} - -/* Export footer. */ -static void -ical_export_footer (FILE *stream) -{ - (void)fprintf (stream, "END:VCALENDAR\n"); -} - -static void -pcal_export_footer (FILE *stream) -{ -} - -/* Export recurrent events. */ -static void -ical_export_recur_events (FILE *stream) -{ - llist_item_t *i, *j; - char ical_date[BUFSIZ]; - - LLIST_FOREACH (&recur_elist, i) - { - struct recur_event *rev = LLIST_GET_DATA (i); - date_sec2date_fmt (rev->day, ICALDATEFMT, ical_date); - (void)fprintf (stream, "BEGIN:VEVENT\n"); - (void)fprintf (stream, "DTSTART:%s\n", ical_date); - (void)fprintf (stream, "RRULE:FREQ=%s;INTERVAL=%d", - ical_recur_type[rev->rpt->type], rev->rpt->freq); - - if (rev->rpt->until != 0) - { - date_sec2date_fmt (rev->rpt->until, ICALDATEFMT, ical_date); - (void)fprintf (stream, ";UNTIL=%s\n", ical_date); - } - else - (void)fprintf (stream, "\n"); - - if (LLIST_FIRST (&rev->exc)) - { - (void)fprintf (stream, "EXDATE:"); - LLIST_FOREACH (&rev->exc, j) - { - struct excp *exc = LLIST_GET_DATA (j); - date_sec2date_fmt (exc->st, ICALDATEFMT, ical_date); - (void)fprintf (stream, "%s", ical_date); - if (LLIST_NEXT (j)) - (void)fprintf (stream, ","); - else - (void)fprintf (stream, "\n"); - } - } - - (void)fprintf (stream, "SUMMARY:%s\n", rev->mesg); - (void)fprintf (stream, "END:VEVENT\n"); - } -} - -/* Format and dump event data to a pcal formatted file. */ -static void -pcal_dump_event (FILE *stream, long event_date, long event_dur, - char *event_mesg) -{ - char pcal_date[BUFSIZ]; - - date_sec2date_fmt (event_date, "%b %d", pcal_date); - (void)fprintf (stream, "%s %s\n", pcal_date, event_mesg); -} - -/* Format and dump appointment data to a pcal formatted file. */ -static void -pcal_dump_apoint (FILE *stream, long apoint_date, long apoint_dur, - char *apoint_mesg) -{ - char pcal_date[BUFSIZ], pcal_beg[BUFSIZ], pcal_end[BUFSIZ]; - - date_sec2date_fmt (apoint_date, "%b %d", pcal_date); - date_sec2date_fmt (apoint_date, "%R", pcal_beg); - date_sec2date_fmt (apoint_date + apoint_dur, "%R", pcal_end); - (void)fprintf (stream, "%s ", pcal_date); - (void)fprintf (stream, "(%s -> %s) %s\n", pcal_beg, pcal_end, apoint_mesg); -} - -static void -pcal_export_recur_events (FILE *stream) -{ - llist_item_t *i; - char pcal_date[BUFSIZ]; - - (void)fprintf (stream, "\n# ============="); - (void)fprintf (stream, "\n# Recur. Events"); - (void)fprintf (stream, "\n# =============\n"); - (void)fprintf (stream, - "# (pcal does not support from..until dates specification\n"); - - LLIST_FOREACH (&recur_elist, i) - { - struct recur_event *rev = LLIST_GET_DATA (i); - if (rev->rpt->until == 0 && rev->rpt->freq == 1) - { - switch (rev->rpt->type) - { - case RECUR_DAILY: - date_sec2date_fmt (rev->day, "%b %d", pcal_date); - (void)fprintf (stream, "all day on_or_after %s %s\n", - pcal_date, rev->mesg); - break; - case RECUR_WEEKLY: - date_sec2date_fmt (rev->day, "%a", pcal_date); - (void)fprintf (stream, "all %s on_or_after ", pcal_date); - date_sec2date_fmt (rev->day, "%b %d", pcal_date); - (void)fprintf (stream, "%s %s\n", pcal_date, rev->mesg); - break; - case RECUR_MONTHLY: - date_sec2date_fmt (rev->day, "%d", pcal_date); - (void)fprintf (stream, "day on all %s %s\n", pcal_date, - rev->mesg); - break; - case RECUR_YEARLY: - date_sec2date_fmt (rev->day, "%b %d", pcal_date); - (void)fprintf (stream, "%s %s\n", pcal_date, rev->mesg); - break; - default: - EXIT (_("incoherent repetition type")); - } - } - else - { - const long YEAR_START = calendar_start_of_year (); - const long YEAR_END = calendar_end_of_year (); - - if (rev->day < YEAR_END && rev->day > YEAR_START) - foreach_date_dump (YEAR_END, rev->rpt, &rev->exc, rev->day, 0, - rev->mesg, (cb_dump_t) pcal_dump_event, stream); - } - } -} - -/* Export events. */ -static void -ical_export_events (FILE *stream) -{ - llist_item_t *i; - char ical_date[BUFSIZ]; - - LLIST_FOREACH (&eventlist, i) - { - struct event *ev = LLIST_TS_GET_DATA (i); - date_sec2date_fmt (ev->day, ICALDATEFMT, ical_date); - (void)fprintf (stream, "BEGIN:VEVENT\n"); - (void)fprintf (stream, "DTSTART:%s\n", ical_date); - (void)fprintf (stream, "SUMMARY:%s\n", ev->mesg); - (void)fprintf (stream, "END:VEVENT\n"); - } -} - -static void -pcal_export_events (FILE *stream) -{ - llist_item_t *i; - - (void)fprintf (stream, "\n# ======\n# Events\n# ======\n"); - LLIST_FOREACH (&eventlist, i) - { - struct event *ev = LLIST_TS_GET_DATA (i); - pcal_dump_event (stream, ev->day, 0, ev->mesg); - } - (void)fprintf (stream, "\n"); -} - -/* Export recurrent appointments. */ -static void -ical_export_recur_apoints (FILE *stream) -{ - llist_item_t *i, *j; - char ical_datetime[BUFSIZ]; - char ical_date[BUFSIZ]; - - LLIST_TS_LOCK (&recur_alist_p); - LLIST_TS_FOREACH (&recur_alist_p, i) - { - struct recur_apoint *rapt = LLIST_TS_GET_DATA (i); - - date_sec2date_fmt (rapt->start, ICALDATETIMEFMT, ical_datetime); - (void)fprintf (stream, "BEGIN:VEVENT\n"); - (void)fprintf (stream, "DTSTART:%s\n", ical_datetime); - (void)fprintf (stream, "DURATION:PT0H0M%ldS\n", rapt->dur); - (void)fprintf (stream, "RRULE:FREQ=%s;INTERVAL=%d", - ical_recur_type[rapt->rpt->type], rapt->rpt->freq); - - if (rapt->rpt->until != 0) - { - date_sec2date_fmt (rapt->rpt->until + HOURINSEC, ICALDATEFMT, - ical_date); - (void)fprintf (stream, ";UNTIL=%s\n", ical_date); - } - else - (void)fprintf (stream, "\n"); - - if (LLIST_FIRST (&rapt->exc)) - { - (void)fprintf (stream, "EXDATE:"); - LLIST_FOREACH (&rapt->exc, j) - { - struct excp *exc = LLIST_GET_DATA (j); - date_sec2date_fmt (exc->st, ICALDATEFMT, ical_date); - (void)fprintf (stream, "%s", ical_date); - if (LLIST_NEXT (j)) - (void)fprintf (stream, ","); - else - (void)fprintf (stream, "\n"); - } - } - - (void)fprintf (stream, "SUMMARY:%s\n", rapt->mesg); - if (rapt->state & APOINT_NOTIFY) - ical_export_valarm (stream); - (void)fprintf (stream, "END:VEVENT\n"); - } - LLIST_TS_UNLOCK (&recur_alist_p); -} - -static void -pcal_export_recur_apoints (FILE *stream) -{ - llist_item_t *i; - char pcal_date[BUFSIZ], pcal_beg[BUFSIZ], pcal_end[BUFSIZ]; - - (void)fprintf (stream, "\n# =============="); - (void)fprintf (stream, "\n# Recur. Apoints"); - (void)fprintf (stream, "\n# ==============\n"); - (void)fprintf (stream, - "# (pcal does not support from..until dates specification\n"); - - LLIST_TS_FOREACH (&recur_alist_p, i) - { - struct recur_apoint *rapt = LLIST_TS_GET_DATA (i); - - if (rapt->rpt->until == 0 && rapt->rpt->freq == 1) - { - date_sec2date_fmt (rapt->start, "%R", pcal_beg); - date_sec2date_fmt (rapt->start + rapt->dur, "%R", pcal_end); - switch (rapt->rpt->type) - { - case RECUR_DAILY: - date_sec2date_fmt (rapt->start, "%b %d", pcal_date); - (void)fprintf (stream, "all day on_or_after %s (%s -> %s) %s\n", - pcal_date, pcal_beg, pcal_end, rapt->mesg); - break; - case RECUR_WEEKLY: - date_sec2date_fmt (rapt->start, "%a", pcal_date); - (void)fprintf (stream, "all %s on_or_after ", pcal_date); - date_sec2date_fmt (rapt->start, "%b %d", pcal_date); - (void)fprintf (stream, "%s (%s -> %s) %s\n", pcal_date, - pcal_beg, pcal_end, rapt->mesg); - break; - case RECUR_MONTHLY: - date_sec2date_fmt (rapt->start, "%d", pcal_date); - (void)fprintf (stream, "day on all %s (%s -> %s) %s\n", - pcal_date, pcal_beg, pcal_end, rapt->mesg); - break; - case RECUR_YEARLY: - date_sec2date_fmt (rapt->start, "%b %d", pcal_date); - (void)fprintf (stream, "%s (%s -> %s) %s\n", pcal_date, - pcal_beg, pcal_end, rapt->mesg); - break; - default: - EXIT (_("incoherent repetition type")); - } - } - else - { - const long YEAR_START = calendar_start_of_year (); - const long YEAR_END = calendar_end_of_year (); - - if (rapt->start < YEAR_END && rapt->start > YEAR_START) - foreach_date_dump (YEAR_END, rapt->rpt, &rapt->exc, rapt->start, - rapt->dur, rapt->mesg, - (cb_dump_t)pcal_dump_apoint, stream); - } - } -} - -/* Export appointments. */ -static void -ical_export_apoints (FILE *stream) -{ - llist_item_t *i; - char ical_datetime[BUFSIZ]; - - LLIST_TS_LOCK (&alist_p); - LLIST_TS_FOREACH (&alist_p, i) - { - struct apoint *apt = LLIST_TS_GET_DATA (i); - date_sec2date_fmt (apt->start, ICALDATETIMEFMT, ical_datetime); - (void)fprintf (stream, "BEGIN:VEVENT\n"); - (void)fprintf (stream, "DTSTART:%s\n", ical_datetime); - (void)fprintf (stream, "DURATION:P%ldDT%ldH%ldM%ldS\n", - apt->dur / DAYINSEC, - (apt->dur / HOURINSEC) % 24, - (apt->dur / MININSEC) % 60, - apt->dur % MININSEC); - (void)fprintf (stream, "SUMMARY:%s\n", apt->mesg); - if (apt->state & APOINT_NOTIFY) - ical_export_valarm (stream); - (void)fprintf (stream, "END:VEVENT\n"); + snprintf(stream_name, BUFSIZ, "%s/calcurse.%s", get_tempdir(), + file_ext[type]); + + while (stream == NULL) { + status_mesg(question, ""); + cancel = updatestring(win[STA].p, &stream_name, 0, 1); + if (cancel) { + mem_free(stream_name); + return NULL; } - LLIST_TS_UNLOCK (&alist_p); -} - -static void -pcal_export_apoints (FILE *stream) -{ - llist_item_t *i; - - (void)fprintf (stream, "\n# ============\n# Appointments\n# ============\n"); - LLIST_TS_LOCK (&alist_p); - LLIST_TS_FOREACH (&alist_p, i) - { - struct apoint *apt = LLIST_TS_GET_DATA (i); - pcal_dump_apoint (stream, apt->start, apt->dur, apt->mesg); + stream = fopen(stream_name, "w"); + if (stream == NULL) { + status_mesg(wrong_name, press_enter); + wgetch(win[STA].p); } - LLIST_TS_UNLOCK (&alist_p); - (void)fprintf (stream, "\n"); -} - -/* Export todo items. */ -static void -ical_export_todo (FILE *stream) -{ - llist_item_t *i; - - LLIST_FOREACH (&todolist, i) - { - struct todo *todo = LLIST_TS_GET_DATA (i); - if (todo->id < 0) /* completed items */ - continue; + } + mem_free(stream_name); - (void)fprintf (stream, "BEGIN:VTODO\n"); - (void)fprintf (stream, "PRIORITY:%d\n", todo->id); - (void)fprintf (stream, "SUMMARY:%s\n", todo->mesg); - (void)fprintf (stream, "END:VTODO\n"); - } -} - -static void -pcal_export_todo (FILE *stream) -{ - llist_item_t *i; - - (void)fprintf (stream, "#\n# Todos\n#\n"); - LLIST_FOREACH (&todolist, i) - { - struct todo *todo = LLIST_TS_GET_DATA (i); - if (todo->id < 0) /* completed items */ - continue; - - (void)fprintf (stream, "note all "); - (void)fprintf (stream, "%d. %s\n", todo->id, todo->mesg); - } - (void)fprintf (stream, "\n"); + return stream; } /* Append a line to a file. */ -unsigned -io_fprintln (const char *fname, const char *fmt, ...) +unsigned io_fprintln(const char *fname, const char *fmt, ...) { FILE *fp; va_list ap; char buf[BUFSIZ]; int ret; - fp = fopen (fname, "a"); - RETVAL_IF (!fp, 0, _("Failed to open \"%s\", - %s\n"), - fname, strerror (errno)); + fp = fopen(fname, "a"); + RETVAL_IF(!fp, 0, _("Failed to open \"%s\", - %s\n"), fname, strerror(errno)); - va_start (ap, fmt); - ret = vsnprintf (buf, sizeof buf, fmt, ap); - RETVAL_IF (ret < 0, 0, _("Failed to build message\n")); - va_end (ap); + va_start(ap, fmt); + ret = vsnprintf(buf, sizeof buf, fmt, ap); + RETVAL_IF(ret < 0, 0, _("Failed to build message\n")); + va_end(ap); - ret = fprintf (fp, "%s", buf); - RETVAL_IF (ret < 0, 0, _("Failed to print message \"%s\"\n"), buf); + ret = fprintf(fp, "%s", buf); + RETVAL_IF(ret < 0, 0, _("Failed to print message \"%s\"\n"), buf); - ret = fclose (fp); - RETVAL_IF (ret != 0, 0, _("Failed to close \"%s\" - %s\n"), - fname, strerror (errno)); + ret = fclose(fp); + RETVAL_IF(ret != 0, 0, _("Failed to close \"%s\" - %s\n"), + fname, strerror(errno)); return 1; } @@ -723,383 +218,231 @@ io_fprintln (const char *fname, const char *fmt, ...) * is created. * The datadir argument can be use to specify an alternative data root dir. */ -void -io_init (char *cfile, char *datadir) +void io_init(const char *cfile, const char *datadir) { FILE *data_file; - char *home; + const char *home; char apts_file[BUFSIZ] = ""; int ch; - if (datadir != NULL) - { - home = datadir; - (void)snprintf (path_dir, BUFSIZ, "%s", home); - (void)snprintf (path_todo, BUFSIZ, "%s/" TODO_PATH_NAME, home); - (void)snprintf (path_conf, BUFSIZ, "%s/" CONF_PATH_NAME, home); - (void)snprintf (path_notes, BUFSIZ, "%s/" NOTES_DIR_NAME, home); - (void)snprintf (path_apts, BUFSIZ, "%s/" APTS_PATH_NAME, home); - (void)snprintf (path_keys, BUFSIZ, "%s/" KEYS_PATH_NAME, home); - (void)snprintf (path_cpid, BUFSIZ, "%s/" CPID_PATH_NAME, home); - (void)snprintf (path_dpid, BUFSIZ, "%s/" DPID_PATH_NAME, home); - (void)snprintf (path_dmon_log, BUFSIZ, "%s/" DLOG_PATH_NAME, home); - } - else - { - home = getenv ("HOME"); - if (home == NULL) - { - home = "."; - } - (void)snprintf (path_dir, BUFSIZ, "%s/" DIR_NAME, home); - (void)snprintf (path_todo, BUFSIZ, "%s/" TODO_PATH, home); - (void)snprintf (path_conf, BUFSIZ, "%s/" CONF_PATH, home); - (void)snprintf (path_keys, BUFSIZ, "%s/" KEYS_PATH, home); - (void)snprintf (path_cpid, BUFSIZ, "%s/" CPID_PATH, home); - (void)snprintf (path_dpid, BUFSIZ, "%s/" DPID_PATH, home); - (void)snprintf (path_dmon_log, BUFSIZ, "%s/" DLOG_PATH, home); - (void)snprintf (path_notes, BUFSIZ, "%s/" NOTES_DIR, home); - if (cfile == NULL) - { - (void)snprintf (path_apts, BUFSIZ, "%s/" APTS_PATH, home); - } - else - { - (void)snprintf (apts_file, BUFSIZ, "%s", cfile); - (void)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': - printf (_("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); - printf (_("starting interactive mode...\n")); - } - break; - - default: - printf (_("aborting...\n")); - exit_calcurse (EXIT_FAILURE); - break; - } - } - file_close (data_file, __FILE_POS__); + if (datadir != NULL) { + home = datadir; + snprintf(path_dir, BUFSIZ, "%s", home); + 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); + snprintf(path_dmon_log, BUFSIZ, "%s/" DLOG_PATH_NAME, home); + } else { + home = getenv("HOME"); + if (home == NULL) { + home = "."; + } + snprintf(path_dir, BUFSIZ, "%s/" DIR_NAME, home); + snprintf(path_todo, BUFSIZ, "%s/" TODO_PATH, home); + snprintf(path_conf, BUFSIZ, "%s/" CONF_PATH, home); + snprintf(path_keys, BUFSIZ, "%s/" KEYS_PATH, home); + snprintf(path_cpid, BUFSIZ, "%s/" CPID_PATH, home); + 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); + } 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")); + exit_calcurse(EXIT_FAILURE); + break; } + } + file_close(data_file, __FILE_POS__); } + } } -void -io_extract_data (char *dst_data, const char *org, int len) +void io_extract_data(char *dst_data, const char *org, int len) { int i; - for (i = 0; i < len - 1; i++) - { - if (*org == '\n' || *org == '\0') - break; - *dst_data++ = *org++; - } + for (; *org == ' ' || *org == '\t'; org++) ; + for (i = 0; i < len - 1; i++) { + if (*org == '\n' || *org == '\0' || *org == '#') + break; + *dst_data++ = *org++; + } *dst_data = '\0'; } -void -display_mark (void) +static void display_mark(void) { const int DISPLAY_TIME = 1; WINDOW *mwin; - mwin = newwin (1, 2, 1, col - 3); + mwin = newwin(1, 2, 1, col - 3); - custom_apply_attr (mwin, ATTR_HIGHEST); - mvwprintw (mwin, 0, 0, "**"); - wins_wrefresh (mwin); - sleep (DISPLAY_TIME); - mvwprintw (mwin, 0, 0, " "); - wins_wrefresh (mwin); - delwin (mwin); - wins_doupdate (); + custom_apply_attr(mwin, ATTR_HIGHEST); + mvwprintw(mwin, 0, 0, "**"); + wins_wrefresh(mwin); + sleep(DISPLAY_TIME); + mvwprintw(mwin, 0, 0, " "); + wins_wrefresh(mwin); + delwin(mwin); + wins_doupdate(); } static pthread_mutex_t io_save_mutex = PTHREAD_MUTEX_INITIALIZER; -/* Save the user configuration. */ -unsigned -io_save_conf (struct conf *conf) -{ - char *config_txt = - "#\n" - "# Calcurse configuration file\n#\n" - "# This file sets the configuration options used by Calcurse. These\n" - "# options are usually set from within Calcurse. A line beginning with \n" - "# a space or tab is considered to be a continuation of the previous " - "line.\n" - "# For a variable to be unset its value must be blank.\n" - "# To set a variable to the empty string its value should be \"\".\n" - "# Lines beginning with \"#\" are comments, and ignored by Calcurse.\n"; - char theme_name[BUFSIZ]; - FILE *fp; - - if ((fp = fopen (path_conf, "w")) == NULL) - return 0; - - custom_color_theme_name (theme_name); - - (void)fprintf (fp, "%s\n", config_txt); - - (void)fprintf (fp, "# If this option is set to yes, " - "automatic save is done when quitting\n"); - (void)fprintf (fp, "auto_save=\n"); - (void)fprintf (fp, "%s\n", (conf->auto_save) ? "yes" : "no"); - - (void)fprintf (fp, "\n# If not null, perform automatic saves every " - "'periodic_save' minutes\n"); - (void)fprintf (fp, "periodic_save=\n"); - (void)fprintf (fp, "%d\n", conf->periodic_save); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "confirmation is required before quitting\n"); - (void)fprintf (fp, "confirm_quit=\n"); - (void)fprintf (fp, "%s\n", (conf->confirm_quit) ? "yes" : "no"); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "confirmation is required before deleting an event\n"); - (void)fprintf (fp, "confirm_delete=\n"); - (void)fprintf (fp, "%s\n", (conf->confirm_delete) ? "yes" : "no"); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "messages about loaded and saved data will not be displayed\n"); - (void)fprintf (fp, "skip_system_dialogs=\n"); - (void)fprintf (fp, "%s\n", (conf->skip_system_dialogs) ? "yes" : "no"); - - (void)fprintf (fp, - "\n# If this option is set to yes, progress bar appearing " - "when saving data will not be displayed\n"); - (void)fprintf (fp, "skip_progress_bar=\n"); - (void)fprintf (fp, "%s\n", (conf->skip_progress_bar) ? "yes" : "no"); - - (void)fprintf (fp, "\n# Default calendar view (0)monthly (1)weekly:\n"); - (void)fprintf (fp, "calendar_default_view=\n"); - (void)fprintf (fp, "%d\n", calendar_get_view ()); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "monday is the first day of the week, else it is sunday\n"); - (void)fprintf (fp, "week_begins_on_monday=\n"); - (void)fprintf (fp, "%s\n", - (calendar_week_begins_on_monday ())? "yes" : "no"); - - (void)fprintf (fp, "\n# This is the color theme used for menus :\n"); - (void)fprintf (fp, "color-theme=\n"); - (void)fprintf (fp, "%s\n", theme_name); - - (void)fprintf (fp, "\n# This is the layout of the calendar :\n"); - (void)fprintf (fp, "layout=\n"); - (void)fprintf (fp, "%d\n", wins_layout ()); - - (void)fprintf (fp, "\n# Width (in percentage, 0 being minimun width) " - "of the side bar :\n"); - (void)fprintf (fp, "side-bar_width=\n"); - (void)fprintf (fp, "%d\n", wins_sbar_wperc ()); - - if (ui_mode == UI_CURSES) - pthread_mutex_lock (&nbar.mutex); - (void)fprintf (fp, - "\n# If this option is set to yes, " - "notify-bar will be displayed :\n"); - (void)fprintf (fp, "notify-bar_show=\n"); - (void)fprintf (fp, "%s\n", (nbar.show) ? "yes" : "no"); - - (void)fprintf (fp, - "\n# Format of the date to be displayed inside notify-bar :\n"); - (void)fprintf (fp, "notify-bar_date=\n"); - (void)fprintf (fp, "%s\n", nbar.datefmt); - - (void)fprintf (fp, - "\n# Format of the time to be displayed inside notify-bar :\n"); - (void)fprintf (fp, "notify-bar_clock=\n"); - (void)fprintf (fp, "%s\n", nbar.timefmt); - - (void)fprintf (fp, - "\n# Warn user if he has an appointment within next " - "'notify-bar_warning' seconds :\n"); - (void)fprintf (fp, "notify-bar_warning=\n"); - (void)fprintf (fp, "%d\n", nbar.cntdwn); - - (void)fprintf (fp, "\n# Command used to notify user of " - "an upcoming appointment :\n"); - (void)fprintf (fp, "notify-bar_command=\n"); - (void)fprintf (fp, "%s\n", nbar.cmd); - - (void)fprintf (fp, "\n# Format of the date to be displayed " - "in non-interactive mode :\n"); - (void)fprintf (fp, "output_datefmt=\n"); - (void)fprintf (fp, "%s\n", conf->output_datefmt); - - (void)fprintf (fp, "\n# Format to be used when entering a date " - "(1)mm/dd/yyyy (2)dd/mm/yyyy (3)yyyy/mm/dd) " - "(4)yyyy-mm-dd:\n"); - (void)fprintf (fp, "input_datefmt=\n"); - (void)fprintf (fp, "%d\n", conf->input_datefmt); - - if (ui_mode == UI_CURSES) - pthread_mutex_unlock (&nbar.mutex); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "calcurse will run in background to get notifications " - "after exiting\n"); - (void)fprintf (fp, "notify-daemon_enable=\n"); - (void)fprintf (fp, "%s\n", dmon.enable ? "yes" : "no"); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "activity will be logged when running in background\n"); - (void)fprintf (fp, "notify-daemon_log=\n"); - (void)fprintf (fp, "%s\n", dmon.log ? "yes" : "no"); - - file_close (fp, __FILE_POS__); - - return 1; -} - /* * Save the apts data file, which contains the * appointments first, and then the events. * Recursive items are written first. */ -unsigned -io_save_apts (void) +unsigned io_save_apts(void) { llist_item_t *i; FILE *fp; - if ((fp = fopen (path_apts, "w")) == NULL) + if (read_only) + return 1; + + if ((fp = fopen(path_apts, "w")) == NULL) return 0; - recur_save_data (fp); + recur_save_data(fp); if (ui_mode == UI_CURSES) - LLIST_TS_LOCK (&alist_p); - LLIST_TS_FOREACH (&alist_p, i) - { - struct apoint *apt = LLIST_TS_GET_DATA (i); - apoint_write (apt, fp); - } + LLIST_TS_LOCK(&alist_p); + LLIST_TS_FOREACH(&alist_p, i) { + struct apoint *apt = LLIST_TS_GET_DATA(i); + apoint_write(apt, fp); + } if (ui_mode == UI_CURSES) - LLIST_TS_UNLOCK (&alist_p); + LLIST_TS_UNLOCK(&alist_p); - LLIST_FOREACH (&eventlist, i) - { - struct event *ev = LLIST_TS_GET_DATA (i); - event_write (ev, fp); - } - file_close (fp, __FILE_POS__); + LLIST_FOREACH(&eventlist, i) { + struct event *ev = LLIST_TS_GET_DATA(i); + event_write(ev, fp); + } + file_close(fp, __FILE_POS__); return 1; } /* Save the todo data file. */ -unsigned -io_save_todo (void) +unsigned io_save_todo(void) { llist_item_t *i; FILE *fp; - if ((fp = fopen (path_todo, "w")) == NULL) + if (read_only) + return 1; + + if ((fp = fopen(path_todo, "w")) == NULL) return 0; - LLIST_FOREACH (&todolist, i) - { - struct todo *todo = LLIST_TS_GET_DATA (i); - if (todo->note) - (void)fprintf (fp, "[%d]>%s %s\n", todo->id, todo->note, todo->mesg); - else - (void)fprintf (fp, "[%d] %s\n", todo->id, todo->mesg); - } - file_close (fp, __FILE_POS__); + LLIST_FOREACH(&todolist, i) { + struct todo *todo = LLIST_TS_GET_DATA(i); + todo_write(todo, fp); + } + file_close(fp, __FILE_POS__); return 1; } /* Save user-defined keys */ -unsigned -io_save_keys (void) +unsigned io_save_keys(void) { FILE *fp; - if ((fp = fopen (path_keys, "w")) == NULL) + if (read_only) + return 1; + + if ((fp = fopen(path_keys, "w")) == NULL) return 0; - keys_save_bindings (fp); - file_close (fp, __FILE_POS__); + keys_save_bindings(fp); + file_close(fp, __FILE_POS__); return 1; } /* Save the calendar data */ -void -io_save_cal (struct conf *conf, enum save_display display) +void io_save_cal(enum save_display display) { - char *access_pb = _("Problems accessing data file ..."); - char *save_success = _("The data files were successfully saved"); - char *enter = _("Press [ENTER] to continue"); + const char *access_pb = _("Problems accessing data file ..."); + const char *save_success = _("The data files were successfully saved"); + const char *enter = _("Press [ENTER] to continue"); int show_bar; - pthread_mutex_lock (&io_save_mutex); + if (read_only) + return; + + pthread_mutex_lock(&io_save_mutex); show_bar = 0; if (ui_mode == UI_CURSES && display == IO_SAVE_DISPLAY_BAR - && !conf->skip_progress_bar) + && conf.progress_bar) show_bar = 1; else if (ui_mode == UI_CURSES && display == IO_SAVE_DISPLAY_MARK) - display_mark (); + display_mark(); if (show_bar) - progress_bar (PROGRESS_BAR_SAVE, PROGRESS_BAR_CONF); - if (!io_save_conf (conf)) - ERROR_MSG ("%s", access_pb); + progress_bar(PROGRESS_BAR_SAVE, PROGRESS_BAR_CONF); + if (!config_save()) + ERROR_MSG("%s", access_pb); if (show_bar) - progress_bar (PROGRESS_BAR_SAVE, PROGRESS_BAR_TODO); - if (!io_save_todo ()) - ERROR_MSG ("%s", access_pb); + progress_bar(PROGRESS_BAR_SAVE, PROGRESS_BAR_TODO); + if (!io_save_todo()) + ERROR_MSG("%s", access_pb); if (show_bar) - progress_bar (PROGRESS_BAR_SAVE, PROGRESS_BAR_APTS); - if (!io_save_apts ()) - ERROR_MSG ("%s", access_pb); + progress_bar(PROGRESS_BAR_SAVE, PROGRESS_BAR_APTS); + if (!io_save_apts()) + ERROR_MSG("%s", access_pb); if (show_bar) - progress_bar (PROGRESS_BAR_SAVE, PROGRESS_BAR_KEYS); - if (!io_save_keys ()) - ERROR_MSG ("%s", access_pb); + progress_bar(PROGRESS_BAR_SAVE, PROGRESS_BAR_KEYS); + if (!io_save_keys()) + ERROR_MSG("%s", access_pb); /* Print a message telling data were saved */ - if (ui_mode == UI_CURSES && !conf->skip_system_dialogs - && display != IO_SAVE_DISPLAY_MARK) - { - status_mesg (save_success, enter); - (void)wgetch (win[STA].p); - } + if (ui_mode == UI_CURSES && conf.system_dialogs + && display != IO_SAVE_DISPLAY_MARK) { + status_mesg(save_success, enter); + wgetch(win[STA].p); + } - pthread_mutex_unlock (&io_save_mutex); + pthread_mutex_unlock(&io_save_mutex); } /* @@ -1107,8 +450,7 @@ io_save_cal (struct conf *conf, enum save_display display) * and then load either: a new appointment, a new event, or a new * recursive item (which can also be either an event or an appointment). */ -void -io_load_app (void) +void io_load_app(void) { FILE *data_file; int c, is_appointment, is_event, is_recursive; @@ -1118,251 +460,206 @@ io_load_app (void) int id = 0; int freq; char type, state = 0L; - char note[NOTESIZ + 1], *notep; + char note[MAX_NOTESIZ + 1], *notep; - t = time (NULL); - lt = localtime (&t); + t = time(NULL); + lt = localtime(&t); start = end = until = *lt; - data_file = fopen (path_apts, "r"); - for (;;) - { - LLIST_INIT (&exc); - is_appointment = is_event = is_recursive = 0; - c = getc (data_file); - if (c == EOF) - break; - (void)ungetc (c, data_file); - - /* Read the date first: it is common to both events - * and appointments. - */ - if (fscanf (data_file, "%u / %u / %u ", - &start.tm_mon, &start.tm_mday, &start.tm_year) != 3) - { - EXIT (_("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. - */ - c = getc (data_file); - - if (c == '@') - is_appointment = 1; - else if (c == '[') - is_event = 1; - else - { - EXIT (_("no event nor appointment found")); - } - (void)ungetc (c, data_file); - - /* Read the remaining informations. */ - if (is_appointment) - { - fscanf (data_file, "@ %u : %u -> %u / %u / %u @ %u : %u ", - &start.tm_hour, &start.tm_min, - &end.tm_mon, &end.tm_mday, &end.tm_year, - &end.tm_hour, &end.tm_min); - } - else if (is_event) - { - fscanf (data_file, "[%d] ", &id); - } - else - { - EXIT (_("wrong format in the appointment or event")); - /* NOTREACHED */ - } + data_file = fopen(path_apts, "r"); + EXIT_IF(data_file == NULL, _("failed to open appointment file")); - /* Check if we have a recursive item. */ - c = getc (data_file); - - if (c == '{') - { - (void)ungetc (c, data_file); - is_recursive = 1; - fscanf (data_file, "{ %d%c ", &freq, &type); - - c = getc (data_file); - if (c == '}') - { /* endless recurrent item */ - (void)ungetc (c, data_file); - fscanf (data_file, "} "); - until.tm_year = 0; - } - else if (c == '-') - { - (void)ungetc (c, data_file); - fscanf (data_file, " -> %u / %u / %u ", - &until.tm_mon, &until.tm_mday, &until.tm_year); - c = getc (data_file); - if (c == '!') - { - (void)ungetc (c, data_file); - recur_exc_scan (&exc, data_file); - c = getc (data_file); - } - else - { - (void)ungetc (c, data_file); - fscanf (data_file, "} "); - } - } - else if (c == '!') - { // endless item with exceptions - (void)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")); - /* NOTREACHED */ - } - } - else - (void)ungetc (c, data_file); - - /* Check if a note is attached to the item. */ - c = getc (data_file); - if (c == '>') - { - (void)fgets (note, NOTESIZ + 1, data_file); - note[NOTESIZ] = '\0'; - notep = note; - getc (data_file); - } - else - { - notep = NULL; - (void)ungetc (c, data_file); - } + for (;;) { + LLIST_INIT(&exc); + is_appointment = is_event = is_recursive = 0; + c = getc(data_file); + if (c == EOF) + break; + ungetc(c, data_file); + + /* Read the date first: it is common to both events + * and appointments. + */ + if (fscanf(data_file, "%d / %d / %d ", + &start.tm_mon, &start.tm_mday, &start.tm_year) != 3) + EXIT(_("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. + */ + c = getc(data_file); + + if (c == '@') + is_appointment = 1; + else if (c == '[') + is_event = 1; + else + EXIT(_("no event nor appointment found")); + + /* Read the remaining informations. */ + if (is_appointment) { + if (fscanf(data_file, " %d : %d -> %d / %d / %d @ %d : %d ", + &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")); + } else if (is_event) { + if (fscanf(data_file, " %d ", &id) != 1 || getc(data_file) != ']') + EXIT(_("syntax error in item identifier")); + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else { + EXIT(_("wrong format in the appointment or event")); + /* NOTREACHED */ + } - /* - * Last: read the item description and load it into its - * corresponding linked list, depending on the item type. - */ - if (is_appointment) - { - c = getc (data_file); - if (c == '!') - { - (void)ungetc (c, data_file); - fscanf (data_file, " ! "); - state |= APOINT_NOTIFY; - } - else - { - (void)ungetc (c, data_file); - fscanf (data_file, " | "); - state = 0L; - } - if (is_recursive) - { - recur_apoint_scan (data_file, start, end, - type, freq, until, notep, &exc, state); - } - else - { - apoint_scan (data_file, start, end, state, notep); - } - } - else if (is_event) - { - if (is_recursive) - { - recur_event_scan (data_file, start, id, type, - freq, until, notep, &exc); - } - else - { - event_scan (data_file, start, id, notep); - } - } - else - { - EXIT (_("wrong format in the appointment or event")); - /* NOTREACHED */ - } + /* Check if we have a recursive item. */ + c = getc(data_file); + + if (c == '{') { + is_recursive = 1; + if (fscanf(data_file, " %d%c ", &freq, &type) != 2) + EXIT(_("syntax error in item repetition")); + + c = getc(data_file); + if (c == '}') { /* endless recurrent item */ + until.tm_year = 0; + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else if (c == '-' && getc(data_file) == '>') { + if (fscanf(data_file, " %d / %d / %d ", &until.tm_mon, + &until.tm_mday, &until.tm_year) != 3) + EXIT(_("syntax error in item repetition")); + c = getc(data_file); + if (c == '!') { + ungetc(c, data_file); + recur_exc_scan(&exc, data_file); + c = getc(data_file); + } else if (c == '}') { + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else + EXIT(_("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")); + /* NOTREACHED */ + } + } else + ungetc(c, data_file); + + /* Check if a note is attached to the item. */ + c = getc(data_file); + if (c == '>') { + note_read(note, data_file); + notep = note; + } else { + notep = NULL; + ungetc(c, data_file); + } + + /* + * Last: read the item description and load it into its + * corresponding linked list, depending on the item type. + */ + if (is_appointment) { + c = getc(data_file); + if (c == '!') { + state |= APOINT_NOTIFY; + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else if (c == '|') { + state = 0L; + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else + EXIT(_("syntax error in item repetition")); + if (is_recursive) { + recur_apoint_scan(data_file, start, end, + type, freq, until, notep, &exc, state); + } else { + apoint_scan(data_file, start, end, state, notep); + } + } else if (is_event) { + if (is_recursive) { + recur_event_scan(data_file, start, id, type, freq, until, notep, &exc); + } else { + event_scan(data_file, start, id, notep); + } + } else { + EXIT(_("wrong format in the appointment or event")); + /* NOTREACHED */ } - file_close (data_file, __FILE_POS__); + } + file_close(data_file, __FILE_POS__); } /* Load the todo data */ -void -io_load_todo (void) +void io_load_todo(void) { FILE *data_file; - char *mesg_line1 = _("Failed to open todo file"); - char *mesg_line2 = _("Press [ENTER] to continue"); char *newline; int nb_tod = 0; int c, id; - char buf[BUFSIZ], e_todo[BUFSIZ], note[NOTESIZ + 1]; + char buf[BUFSIZ], e_todo[BUFSIZ], note[MAX_NOTESIZ + 1]; - data_file = fopen (path_todo, "r"); - if (data_file == NULL) - { - status_mesg (mesg_line1, mesg_line2); - (void)wgetch (win[STA].p); - } - for (;;) - { - c = getc (data_file); - if (c == EOF) - { - break; - } - else if (c == '[') - { /* new style with id */ - fscanf (data_file, "%d]", &id); - } - else - { - id = 9; - (void)ungetc (c, data_file); - } - /* Now read the attached note, if any. */ - c = getc (data_file); - if (c == '>') - { - (void)fgets (note, NOTESIZ + 1, data_file); - note[NOTESIZ] = '\0'; - getc (data_file); - } - else - note[0] = '\0'; - /* Then read todo description. */ - (void)fgets (buf, sizeof buf, data_file); - newline = strchr (buf, '\n'); - if (newline) - *newline = '\0'; - io_extract_data (e_todo, buf, sizeof buf); - todo_add (e_todo, id, note); - ++nb_tod; - } - file_close (data_file, __FILE_POS__); - todo_set_nb (nb_tod); + data_file = fopen(path_todo, "r"); + EXIT_IF(data_file == NULL, _("failed to open todo file")); + + for (;;) { + 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")); + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else { + id = 9; + ungetc(c, data_file); + } + /* Now read the attached note, if any. */ + c = getc(data_file); + if (c == '>') + note_read(note, data_file); + else { + note[0] = '\0'; + ungetc(c, data_file); + } + /* Then read todo description. */ + if (!fgets(buf, sizeof buf, data_file)) + buf[0] = '\0'; + newline = strchr(buf, '\n'); + if (newline) + *newline = '\0'; + io_extract_data(e_todo, buf, sizeof buf); + todo_add(e_todo, id, note); + ++nb_tod; + } + file_close(data_file, __FILE_POS__); + todo_set_nb(nb_tod); } static void -load_keys_ht_getkey (struct ht_keybindings_s *data, char **key, int *len) +load_keys_ht_getkey(struct ht_keybindings_s *data, const char **key, int *len) { *key = data->label; - *len = strlen (data->label); + *len = strlen(data->label); } static int -load_keys_ht_compare (struct ht_keybindings_s *data1, - struct ht_keybindings_s *data2) +load_keys_ht_compare(struct ht_keybindings_s *data1, + struct ht_keybindings_s *data2) { - const int KEYLEN = strlen (data1->label); + const int KEYLEN = strlen(data1->label); - if (strlen (data2->label) == KEYLEN - && !memcmp (data1->label, data2->label, KEYLEN)) + if (strlen(data2->label) == KEYLEN + && !memcmp(data1->label, data2->label, KEYLEN)) return 0; else return 1; @@ -1373,7 +670,7 @@ load_keys_ht_compare (struct ht_keybindings_s *data1, * visible in some specific cases. Thus replace it by the following is_blank() * function. */ -static int is_blank (int c) +static int is_blank(int c) { return c == ' ' || c == '\t'; } @@ -1385,8 +682,7 @@ static int is_blank (int c) * A log file is also built in case some errors were found in the key * configuration file. */ -void -io_load_keys (char *pager) +void io_load_keys(const char *pager) { struct ht_keybindings_s keys[NBKEYS]; FILE *keyfp; @@ -1395,187 +691,163 @@ io_load_keys (char *pager) int i, skipped, loaded, line; const int MAX_ERRORS = 5; - keys_init (); + keys_init(); -#define HSIZE 256 - HTABLE_HEAD (ht_keybindings, HSIZE, ht_keybindings_s) ht_keys = - HTABLE_INITIALIZER (&ht_keys); + struct ht_keybindings ht_keys = HTABLE_INITIALIZER(&ht_keys); - HTABLE_GENERATE (ht_keybindings, ht_keybindings_s, load_keys_ht_getkey, - load_keys_ht_compare); + for (i = 0; i < NBKEYS; i++) { + keys[i].key = (enum key)i; + keys[i].label = keys_get_label((enum key)i); + HTABLE_INSERT(ht_keybindings, &ht_keys, &keys[i]); + } - for (i = 0; i < NBKEYS; i++) - { - keys[i].key = (enum key)i; - keys[i].label = keys_get_label ((enum key)i); - HTABLE_INSERT (ht_keybindings, &ht_keys, &keys[i]); - } + keyfp = fopen(path_keys, "r"); + EXIT_IF(keyfp == NULL, _("failed to open key file")); - keyfp = fopen (path_keys, "r"); - EXIT_IF (keyfp == NULL, _("could not find any key file.")); - log = io_log_init (); + log = io_log_init(); skipped = loaded = line = 0; - while (fgets (buf, BUFSIZ, keyfp) != NULL) - { - char key_label[BUFSIZ], *p; - struct ht_keybindings_s *ht_elm, ht_entry; - const int AWAITED = 1; - int assigned; - - line++; - if (skipped > MAX_ERRORS) - { - char *too_many = - _("\nToo many errors while reading configuration file!\n" - "Please backup your keys file, remove it from directory, " - "and launch calcurse again.\n"); - - io_log_print (log, line, too_many); - break; - } - for (p = buf; is_blank ((int)*p); p++) - ; - if (p != buf) - memmove (buf, p, strlen (p)); - if (buf[0] == '#' || buf[0] == '\n') - continue; - - if (sscanf (buf, "%s", key_label) != AWAITED) - { - skipped++; - io_log_print (log, line, _("Could not read key label")); - continue; - } - ht_entry.label = key_label; - p = buf + strlen (key_label) + 1; - ht_elm = HTABLE_LOOKUP (ht_keybindings, &ht_keys, &ht_entry); - if (!ht_elm) - { + while (fgets(buf, BUFSIZ, keyfp) != NULL) { + char key_label[BUFSIZ], *p; + struct ht_keybindings_s *ht_elm, ht_entry; + const int AWAITED = 1; + int assigned; + + line++; + if (skipped > MAX_ERRORS) { + const char *too_many = + _("\nToo many errors while reading configuration file!\n" + "Please backup your keys file, remove it from directory, " + "and launch calcurse again.\n"); + + io_log_print(log, line, too_many); + break; + } + for (p = buf; is_blank((int)*p); p++) ; + if (p != buf) + memmove(buf, p, strlen(p)); + if (buf[0] == '#' || buf[0] == '\n') + continue; + + if (sscanf(buf, "%s", key_label) != AWAITED) { + skipped++; + io_log_print(log, line, _("Could not read key label")); + continue; + } + ht_entry.label = key_label; + p = buf + strlen(key_label) + 1; + ht_elm = HTABLE_LOOKUP(ht_keybindings, &ht_keys, &ht_entry); + if (!ht_elm) { + skipped++; + io_log_print(log, line, _("Key label not recognized")); + continue; + } + assigned = 0; + for (;;) { + char key_ch[BUFSIZ], tmpbuf[BUFSIZ]; + + while (*p == ' ') + p++; + (void)strncpy(tmpbuf, p, BUFSIZ); + if (sscanf(tmpbuf, "%s", key_ch) == AWAITED) { + int ch; + + if ((ch = keys_str2int(key_ch)) < 0) { + char unknown_key[BUFSIZ]; + skipped++; - io_log_print (log, line, _("Key label not recognized")); - continue; - } - assigned = 0; - for (;;) - { - char key_ch[BUFSIZ], tmpbuf[BUFSIZ]; - - while (*p == ' ') - p++; - (void)strncpy (tmpbuf, p, BUFSIZ); - if (sscanf (tmpbuf, "%s", key_ch) == AWAITED) - { - int ch; - - if ((ch = keys_str2int (key_ch)) < 0) - { - char unknown_key[BUFSIZ]; - - skipped++; - (void)snprintf (unknown_key, BUFSIZ, - _("Error reading key: \"%s\""), key_ch); - io_log_print (log, line, unknown_key); - } - else - { - int used; - - used = keys_assign_binding (ch, ht_elm->key); - if (used) - { - char already_assigned[BUFSIZ]; - - skipped++; - (void)snprintf (already_assigned, BUFSIZ, - _("\"%s\" assigned multiple times!"), key_ch); - io_log_print (log, line, already_assigned); - } - else - assigned++; - } - p += strlen (key_ch) + 1; - } - else - { - if (assigned) - loaded++; - break; - } - } + (void)snprintf(unknown_key, BUFSIZ, + _("Error reading key: \"%s\""), key_ch); + io_log_print(log, line, unknown_key); + } else { + int used; + + used = keys_assign_binding(ch, ht_elm->key); + if (used) { + char already_assigned[BUFSIZ]; + + skipped++; + (void)snprintf(already_assigned, BUFSIZ, + _("\"%s\" assigned multiple times!"), key_ch); + io_log_print(log, line, already_assigned); + } else + assigned++; + } + p += strlen(key_ch) + 1; + } else { + if (assigned) + loaded++; + break; + } } - file_close (keyfp, __FILE_POS__); - file_close (log->fd, __FILE_POS__); - if (skipped > 0) - { - char *view_log = + } + file_close(keyfp, __FILE_POS__); + file_close(log->fd, __FILE_POS__); + if (skipped > 0) { + const char *view_log = _("There were some errors when loading keys file, see log file ?"); - io_log_display (log, view_log, pager); - } - io_log_free (log); - EXIT_IF (skipped > MAX_ERRORS, - _("Too many errors while reading keys file, aborting...")); + io_log_display(log, view_log, pager); + } + io_log_free(log); + EXIT_IF(skipped > MAX_ERRORS, + _("Too many errors while reading keys file, aborting...")); if (loaded < NBKEYS) - keys_fill_missing (); - if (keys_check_missing_bindings ()) - WARN_MSG (_("Some actions do not have any associated key bindings!")); -#undef HSIZE + keys_fill_missing(); + if (keys_check_missing_bindings()) + WARN_MSG(_("Some actions do not have any associated key bindings!")); } -void -io_check_dir (char *dir, int *missing) +void io_check_dir(char *dir, int *missing) { + if (read_only) + return; + errno = 0; - if (mkdir (dir, 0700) != 0) - { - if (errno != EEXIST) - { - (void)fprintf (stderr, _("FATAL ERROR: could not create %s: %s\n"), - dir, strerror (errno)); - exit_calcurse (EXIT_FAILURE); - } - } - else - { - if (missing) - (*missing)++; + if (mkdir(dir, 0700) != 0) { + if (errno != EEXIST) { + fprintf(stderr, _("FATAL ERROR: could not create %s: %s\n"), dir, + strerror(errno)); + exit_calcurse(EXIT_FAILURE); } + } else { + if (missing) + (*missing)++; + } } -unsigned -io_file_exist (char *file) +unsigned io_file_exist(char *file) { FILE *fd; if (!file) return 0; - if ((fd = fopen (file, "r")) == NULL) + if ((fd = fopen(file, "r")) == NULL) return 0; - (void)fclose (fd); + fclose(fd); return 1; } -void -io_check_file (char *file, int *missing) +void io_check_file(char *file, int *missing) { + if (read_only) + return; + errno = 0; - if (!io_file_exist (file)) - { - FILE *fd; - - if (missing) - (*missing)++; - if ((fd = fopen (file, "w")) == NULL) - { - (void)fprintf (stderr, _("FATAL ERROR: could not create %s: %s\n"), - file, strerror (errno)); - exit_calcurse (EXIT_FAILURE); - } - file_close (fd, __FILE_POS__); + if (!io_file_exist(file)) { + 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__); + } } /* @@ -1590,1121 +862,127 @@ io_check_file (char *file, int *missing) * |___ apts * |___ todo */ -int -io_check_data_files (void) +int io_check_data_files(void) { int missing, missing_keys; 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++; - keys_dump_defaults (path_keys); - } + 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++; + keys_dump_defaults(path_keys); + } return missing; } /* Draw the startup screen */ -void -io_startup_screen (unsigned skip_dialogs, int no_data_file) +void io_startup_screen(int no_data_file) { - char *welcome_mesg = - _("Welcome to Calcurse. Missing data files were created."); - char *data_mesg = _("Data files found. Data will be loaded now."); - char *enter = _("Press [ENTER] to continue"); - - if (no_data_file != 0) - { - status_mesg (welcome_mesg, enter); - (void)wgetch (win[STA].p); - } - else if (!skip_dialogs) - { - status_mesg (data_mesg, enter); - (void)wgetch (win[STA].p); - } + const char *enter = _("Press [ENTER] to continue"); + + if (no_data_file) + status_mesg(_("Data files found. Data will be loaded now."), enter); + else + status_mesg(_("Welcome to Calcurse. Missing data files were created."), + enter); + + wgetch(win[STA].p); } /* Export calcurse data. */ -void -io_export_data (enum export_type type, struct conf *conf) +void io_export_data(enum export_type type) { FILE *stream; - char *success = _("The data were successfully exported"); - char *enter = _("Press [ENTER] to continue"); + 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")); + EXIT(_("unknown export type")); stream = 0; - switch (ui_mode) - { - case UI_CMDLINE: - stream = stdout; - break; - case UI_CURSES: - stream = get_export_stream (type); - break; - default: - EXIT (_("wrong export mode")); - /* NOTREACHED */ - } + switch (ui_mode) { + case UI_CMDLINE: + stream = stdout; + break; + case UI_CURSES: + stream = get_export_stream(type); + break; + default: + EXIT(_("wrong export mode")); + /* NOTREACHED */ + } if (stream == NULL) return; - cb_export_header[type] (stream); - - if (!conf->skip_progress_bar && ui_mode == UI_CURSES) - progress_bar (PROGRESS_BAR_EXPORT, PROGRESS_BAR_EXPORT_EVENTS); - cb_export_recur_events[type] (stream); - cb_export_events[type] (stream); - - if (!conf->skip_progress_bar && ui_mode == UI_CURSES) - progress_bar (PROGRESS_BAR_EXPORT, PROGRESS_BAR_EXPORT_APOINTS); - cb_export_recur_apoints[type] (stream); - cb_export_apoints[type] (stream); + if (type == IO_EXPORT_ICAL) + ical_export_data(stream); + else if (type == IO_EXPORT_PCAL) + pcal_export_data(stream); - if (!conf->skip_progress_bar && ui_mode == UI_CURSES) - progress_bar (PROGRESS_BAR_EXPORT, PROGRESS_BAR_EXPORT_TODO); - cb_export_todo[type] (stream); - - cb_export_footer[type] (stream); - - if (stream != stdout) - file_close (stream, __FILE_POS__); - - if (!conf->skip_system_dialogs && ui_mode == UI_CURSES) - { - status_mesg (success, enter); - (void)wgetch (win[STA].p); - } + if (conf.system_dialogs && ui_mode == UI_CURSES) { + status_mesg(success, enter); + wgetch(win[STA].p); + } } /* Draws the export format selection bar */ -void -io_export_bar (void) +void io_export_bar(void) { int smlspc, spc; smlspc = 2; spc = 15; - custom_apply_attr (win[STA].p, ATTR_HIGHEST); - mvwprintw (win[STA].p, 0, 2, "Q"); - mvwprintw (win[STA].p, 1, 2, "I"); - mvwprintw (win[STA].p, 0, 2 + spc, "P"); - custom_remove_attr (win[STA].p, ATTR_HIGHEST); - - mvwprintw (win[STA].p, 0, 2 + smlspc, _("Exit")); - mvwprintw (win[STA].p, 1, 2 + smlspc, _("Ical")); - mvwprintw (win[STA].p, 0, 2 + spc + smlspc, _("Pcal")); - - wnoutrefresh (win[STA].p); - wmove (win[STA].p, 0, 0); - wins_doupdate (); -} - -/* Print a header to describe import log report format. */ -static void -ical_log_init (FILE *log, float version) -{ - const char *header = - "+-------------------------------------------------------------------+\n" - "| Calcurse icalendar import log. |\n" - "| |\n" - "| Items imported from icalendar file, version %1.1f |\n" - "| Some items could not be imported, they are described hereafter. |\n" - "| The log line format is as follows: |\n" - "| |\n" - "| TYPE [LINE]: DESCRIPTION |\n" - "| |\n" - "| where: |\n" - "| * TYPE represents the item type ('VEVENT' or 'VTODO') |\n" - "| * LINE is the line in the input stream at which this item begins |\n" - "| * DESCRIPTION indicates why the item could not be imported |\n" - "+-------------------------------------------------------------------+\n\n"; - - if (log) - (void)fprintf (log, header, version); -} - -/* - * Used to build a report of the import process. - * The icalendar item for which a problem occurs is mentioned (by giving its - * first line inside the icalendar file), together with a message describing the - * problem. - */ -static void -ical_log (FILE *log, ical_types_e type, unsigned lineno, char *msg) -{ - const char *typestr[ICAL_TYPES] = {"VEVENT", "VTODO"}; - - RETURN_IF (type < 0 || type >= ICAL_TYPES, _("unknown ical type")); - if (log) - (void)fprintf (log, "%s [%d]: %s\n", typestr[type], lineno, msg); -} - -static void -ical_store_todo (int priority, char *mesg, char *note) -{ - todo_add (mesg, priority, note); - mem_free (mesg); - erase_note (¬e, ERASE_FORCE_KEEP_NOTE); -} - -static void -ical_store_event (char *mesg, char *note, long day, long end, ical_rpt_t *rpt, - llist_t *exc) -{ - const int EVENTID = 1; - - if (rpt) - { - recur_event_new (mesg, note, day, EVENTID, rpt->type, rpt->freq, - rpt->until, exc); - mem_free (rpt); - } - else if (end && end != day) - { - /* Here we have an event that spans over several days. */ - rpt = mem_malloc (sizeof (ical_rpt_t)); - rpt->type = RECUR_DAILY; - rpt->freq = 1; - rpt->count = 0; - rpt->until = end; - recur_event_new (mesg, note, day, EVENTID, rpt->type, rpt->freq, - rpt->until, exc); - mem_free (rpt); - } - else - { - event_new (mesg, note, day, EVENTID); - } - mem_free (mesg); - erase_note (¬e, ERASE_FORCE_KEEP_NOTE); -} - -static void -ical_store_apoint (char *mesg, char *note, long start, long dur, - ical_rpt_t *rpt, llist_t *exc, int has_alarm) -{ - char state = 0L; - - if (has_alarm) - state |= APOINT_NOTIFY; - if (rpt) - { - recur_apoint_new (mesg, note, start, dur, state, rpt->type, rpt->freq, - rpt->until, exc); - mem_free (rpt); - } - else - { - apoint_new (mesg, note, start, dur, state); - } - mem_free (mesg); - erase_note (¬e, ERASE_FORCE_KEEP_NOTE); -} - -/* - * Returns an allocated string representing the string given in argument once - * unformatted. - * - * Note: - * Even if the RFC2445 recommends not to have more than 75 octets on one line of - * text, I prefer not to restrict the parsing to this size, thus I use a buffer - * of size BUFSIZ. - * - * Extract from RFC2445: - * Lines of text SHOULD NOT be longer than 75 octets, excluding the line - * break. - */ -static char * -ical_unformat_line (char *line) -{ - char *p, uline[BUFSIZ]; - int len; - - if (strlen (line) >= BUFSIZ) - return NULL; - - bzero (uline, BUFSIZ); - for (len = 0, p = line; *p; p++) - { - switch (*p) - { - case '\\': - switch (*(p + 1)) - { - case 'n': - uline[len++] = '\n'; - p++; - break; - case 't': - uline[len++] = '\t'; - p++; - break; - case ';': - case ':': - case ',': - uline[len++] = *(p + 1); - p++; - break; - default: - uline[len++] = *p; - break; - } - break; - default: - uline[len++] = *p; - break; - } - } - - return mem_strdup (uline); -} - -static void -ical_readline_init (FILE *fdi, char *buf, char *lstore, unsigned *ln) -{ - char *eol; - - *buf = *lstore = '\0'; - fgets (lstore, BUFSIZ, fdi); - if ((eol = strchr(lstore, '\n')) != NULL) - *eol = '\0'; - (*ln)++; -} - -static int -ical_readline (FILE *fdi, char *buf, char *lstore, unsigned *ln) -{ - char *eol; - - strncpy (buf, lstore, BUFSIZ); - (*ln)++; - - while (fgets (lstore, BUFSIZ, fdi) != NULL) - { - if ((eol = strchr(lstore, '\n')) != NULL) - *eol = '\0'; - if (*lstore != SPACE && *lstore != TAB) - break; - strncat (buf, lstore + 1, BUFSIZ); - buf[BUFSIZ - 1] = '\0'; - (*ln)++; - } - - if (feof (fdi)) - { - *lstore = '\0'; - if (*buf == '\0') - return 0; - } - - return 1; -} - -static float -ical_chk_header (FILE *fd, char *buf, char *lstore, unsigned *lineno) -{ - const int HEADER_MALFORMED = -1; - const struct string icalheader = STRING_BUILD ("BEGIN:VCALENDAR"); - float version; - - if (!ical_readline (fd, buf, lstore, lineno)) - return HEADER_MALFORMED; - - str_toupper (buf); - if (strncmp (buf, icalheader.str, icalheader.len) != 0) - return HEADER_MALFORMED; - - while (!sscanf (buf, "VERSION:%f", &version)) - { - if (!ical_readline (fd, buf, lstore, lineno)) - return HEADER_MALFORMED; - } - return version; -} - -/* - * iCalendar date-time format is based on the ISO 8601 complete - * representation. It should be something like : DATE 'T' TIME - * where DATE is 'YYYYMMDD' and TIME is 'HHMMSS'. - * The time and 'T' separator are optional (in the case of an day-long event). - * - * Optionnaly, if the type pointer is given, specify if it is an event - * (no time is given, meaning it is an all-day event), or an appointment - * (time is given). - * - * The timezone is not yet handled by calcurse. - */ -static long -ical_datetime2long (char *datestr, ical_vevent_e *type) -{ - const int NOTFOUND = 0, FORMAT_DATE = 3, FORMAT_DATETIME = 5; - struct date date; - unsigned hour, min; - long datelong; - int format; - - format = sscanf (datestr, "%04u%02u%02uT%02u%02u", - &date.yyyy, &date.mm, &date.dd, &hour, &min); - if (format == FORMAT_DATE) - { - if (type) - *type = EVENT; - datelong = date2sec (date, 0, 0); - } - else if (format == FORMAT_DATETIME) - { - if (type) - *type = APPOINTMENT; - datelong = date2sec (date, hour, min); - } - else - { - datelong = NOTFOUND; - } - return datelong; -} - -static long -ical_durtime2long (char *timestr) -{ - long timelong; - char *p; - - if ((p = strchr (timestr, 'T')) == NULL) - timelong = 0; - else - { - int nbmatch; - struct { - unsigned hour, min, sec; - } time; - - p++; - bzero (&time, sizeof time); - nbmatch = sscanf (p, "%uH%uM%uS", &time.hour, &time.min, &time.sec); - if (nbmatch < 1 || nbmatch > 3) - timelong = 0; - else - timelong = time.hour * HOURINSEC + time.min * MININSEC + time.sec; - } - return timelong; -} - -/* - * Extract from RFC2445: - * - * Value Name: DURATION - * - * Purpose: This value type is used to identify properties that contain - * duration of time. - * - * Formal Definition: The value type is defined by the following - * notation: - * - * dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week) - * dur-date = dur-day [dur-time] - * dur-time = "T" (dur-hour / dur-minute / dur-second) - * dur-week = 1*DIGIT "W" - * dur-hour = 1*DIGIT "H" [dur-minute] - * dur-minute = 1*DIGIT "M" [dur-second] - * dur-second = 1*DIGIT "S" - * dur-day = 1*DIGIT "D" - * - * Example: A duration of 15 days, 5 hours and 20 seconds would be: - * P15DT5H0M20S - * A duration of 7 weeks would be: - * P7W - */ -static long -ical_dur2long (char *durstr) -{ - const int NOTFOUND = -1; - long durlong; - char *p; - struct { - unsigned week, day; - } date; - - bzero (&date, sizeof date); - if ((p = strchr (durstr, 'P')) == NULL) - durlong = NOTFOUND; - else - { - p++; - if (*p == '-') - return NOTFOUND; - else if (*p == '+') - p++; - - if (*p == 'T') /* dur-time */ - durlong = ical_durtime2long (p); - else if (strchr (p, 'W')) /* dur-week */ - { - if (sscanf (p, "%u", &date.week) == 1) - durlong = date.week * WEEKINDAYS * DAYINSEC; - else - durlong = NOTFOUND; - } - else - { - if (strchr (p, 'D')) /* dur-date */ - { - if (sscanf (p, "%uD", &date.day) == 1) - { - durlong = date.day * DAYINSEC; - durlong += ical_durtime2long (p); - } - else - durlong = NOTFOUND; - } - else - durlong = NOTFOUND; - } - } - return durlong; -} - -/* - * Compute the vevent repetition end date from the repetition count. - * - * Extract from RFC2445: - * The COUNT rule part defines the number of occurrences at which to - * range-bound the recurrence. The "DTSTART" property value, if specified, - * counts as the first occurrence. - */ -static long -ical_compute_rpt_until (long start, ical_rpt_t *rpt) -{ - long until; - - switch (rpt->type) - { - case RECUR_DAILY: - until = date_sec_change (start, 0, rpt->freq * (rpt->count - 1)); - break; - case RECUR_WEEKLY: - until = date_sec_change (start, 0, - rpt->freq * WEEKINDAYS * (rpt->count - 1)); - break; - case RECUR_MONTHLY: - until = date_sec_change (start, rpt->freq * (rpt->count - 1), 0); - break; - case RECUR_YEARLY: - until = date_sec_change (start, rpt->freq * 12 * (rpt->count - 1), 0); - break; - default: - until = 0; - break; - /* NOTREACHED */ - } - return until; -} - -/* - * Read a recurrence rule from an iCalendar RRULE string. - * - * Value Name: RECUR - * - * Purpose: This value type is used to identify properties that contain - * a recurrence rule specification. - * - * Formal Definition: The value type is defined by the following - * notation: - * - * recur = "FREQ"=freq *( - * - * ; either UNTIL or COUNT may appear in a 'recur', - * ; but UNTIL and COUNT MUST NOT occur in the same 'recur' - * - * ( ";" "UNTIL" "=" enddate ) / - * ( ";" "COUNT" "=" 1*DIGIT ) / - * - * ; the rest of these keywords are optional, - * ; but MUST NOT occur more than - * ; once - * - * ( ";" "INTERVAL" "=" 1*DIGIT ) / - * ( ";" "BYSECOND" "=" byseclist ) / - * ( ";" "BYMINUTE" "=" byminlist ) / - * ( ";" "BYHOUR" "=" byhrlist ) / - * ( ";" "BYDAY" "=" bywdaylist ) / - * ( ";" "BYMONTHDAY" "=" bymodaylist ) / - * ( ";" "BYYEARDAY" "=" byyrdaylist ) / - * ( ";" "BYWEEKNO" "=" bywknolist ) / - * ( ";" "BYMONTH" "=" bymolist ) / - * ( ";" "BYSETPOS" "=" bysplist ) / - * ( ";" "WKST" "=" weekday ) / - * ( ";" x-name "=" text ) - * ) -*/ -static ical_rpt_t * -ical_read_rrule (FILE *log, char *rrulestr, unsigned *noskipped, - const int itemline) -{ - const struct string daily = STRING_BUILD ("DAILY"); - const struct string weekly = STRING_BUILD ("WEEKLY"); - const struct string monthly = STRING_BUILD ("MONTHLY"); - const struct string yearly = STRING_BUILD ("YEARLY"); - const struct string count = STRING_BUILD ("COUNT="); - const struct string interv = STRING_BUILD ("INTERVAL="); - unsigned interval; - ical_rpt_t *rpt; - char *p; - - rpt = NULL; - if ((p = strchr (rrulestr, ':')) != NULL) - { - char freqstr[BUFSIZ]; - - p++; - rpt = mem_malloc (sizeof (ical_rpt_t)); - bzero (rpt, sizeof (ical_rpt_t)); - if (sscanf (p, "FREQ=%s", freqstr) != 1) - { - ical_log (log, ICAL_VEVENT, itemline, - _("recurrence frequence not found.")); - (*noskipped)++; - mem_free (rpt); - return NULL; - } - else - { - if (strncmp (freqstr, daily.str, daily.len) == 0) - rpt->type = RECUR_DAILY; - else if (strncmp (freqstr, weekly.str, weekly.len) == 0) - rpt->type = RECUR_WEEKLY; - else if (strncmp (freqstr, monthly.str, monthly.len) == 0) - rpt->type = RECUR_MONTHLY; - else if (strncmp (freqstr, yearly.str, yearly.len) == 0) - rpt->type = RECUR_YEARLY; - else - { - ical_log (log, ICAL_VEVENT, itemline, - _("recurrence frequence not recognized.")); - (*noskipped)++; - mem_free (rpt); - return NULL; - } - } - /* - The UNTIL rule part defines a date-time value which bounds the - recurrence rule in an inclusive manner. If not present, and the - COUNT rule part is also not present, the RRULE is considered to - repeat forever. - - The COUNT rule part defines the number of occurrences at which to - range-bound the recurrence. The "DTSTART" property value, if - specified, counts as the first occurrence. - */ - if ((p = strstr (rrulestr, "UNTIL")) != NULL) - { - char *untilstr; - - untilstr = strchr (p, '='); - rpt->until = ical_datetime2long (++untilstr, NULL); - } - else - { - unsigned cnt; - char *countstr; - - if ((countstr = strstr (rrulestr, count.str)) != NULL) - { - countstr += count.len; - if (sscanf (countstr, "%u", &cnt) != 1) - { - rpt->until = 0; - /* endless repetition */ - } - else - { - rpt->count = cnt; - } - } - else - rpt->until = 0; - } - - if ((p = strstr (rrulestr, interv.str)) != NULL) - { - p += interv.len; - if (sscanf (p, "%u", &interval) != 1) - { - rpt->freq = 1; - /* default frequence if none specified */ - } - else - { - rpt->freq = interval; - } - } - else - { - rpt->freq = 1; - } - } - else - { - ical_log (log, ICAL_VEVENT, itemline, _("recurrence rule malformed.")); - (*noskipped)++; - } - return rpt; -} + custom_apply_attr(win[STA].p, ATTR_HIGHEST); + mvwprintw(win[STA].p, 0, 2, "Q"); + mvwprintw(win[STA].p, 1, 2, "I"); + mvwprintw(win[STA].p, 0, 2 + spc, "P"); + custom_remove_attr(win[STA].p, ATTR_HIGHEST); -static void -ical_add_exc (llist_t *exc_head, long date) -{ - if (date != 0) - { - struct excp *exc = mem_malloc (sizeof (struct excp)); - exc->st = date; + mvwprintw(win[STA].p, 0, 2 + smlspc, _("Exit")); + mvwprintw(win[STA].p, 1, 2 + smlspc, _("Ical")); + mvwprintw(win[STA].p, 0, 2 + spc + smlspc, _("Pcal")); - LLIST_ADD (exc_head, exc); - } + wnoutrefresh(win[STA].p); + wmove(win[STA].p, 0, 0); + wins_doupdate(); } -/* - * This property defines the list of date/time exceptions for a - * recurring calendar component. - */ -void -ical_read_exdate (llist_t *exc, FILE *log, char *exstr, unsigned *noskipped, - const int itemline) -{ - char *p, *q; - long date; - - LLIST_INIT (exc); - if ((p = strchr (exstr, ':')) != NULL) - { - p++; - while ((q = strchr (p, ',')) != NULL) - { - char buf[BUFSIZ]; - const int buflen = q - p; - - (void)strncpy (buf, p, buflen); - buf[buflen] = '\0'; - date = ical_datetime2long (buf, NULL); - ical_add_exc (exc, date); - p = ++q; - } - date = ical_datetime2long (p, NULL); - ical_add_exc (exc, date); - } - else - { - ical_log (log, ICAL_VEVENT, itemline, - _("recurrence exception dates malformed.")); - (*noskipped)++; - } -} - -/* Return an allocated string containing the name of the newly created note. */ -static char * -ical_read_note (char *line, unsigned *noskipped, ical_vevent_e item_type, - const int itemline, FILE *log) -{ - char *p, *notestr, *notename, fullnotename[BUFSIZ]; - FILE *fdo; - - if ((p = strchr (line, ':')) != NULL) - { - notename = new_tempfile (path_notes, NOTESIZ); - EXIT_IF (notename == NULL, - _("Warning: could not create new note file to store " - "description. Aborting...\n")); - (void)snprintf (fullnotename, BUFSIZ, "%s%s", path_notes, notename); - fdo = fopen (fullnotename, "w"); - EXIT_IF (fdo == NULL, _("Warning: could not open %s, Aborting..."), - fullnotename); - p++; - notestr = ical_unformat_line (p); - if (notestr == NULL) - { - ical_log (log, item_type, itemline, - _("could not get entire item description.")); - file_close (fdo, __FILE_POS__); - erase_note (¬ename, ERASE_FORCE); - (*noskipped)++; - return NULL; - } - else if (strlen (notestr) == 0) - { - file_close (fdo, __FILE_POS__); - erase_note (¬ename, ERASE_FORCE); - mem_free (notestr); - return NULL; - } - else - { - (void)fprintf (fdo, "%s", notestr); - file_close (fdo, __FILE_POS__); - mem_free (notestr); - return notename; - } - } - else - { - ical_log (log, item_type, itemline, _("description malformed.")); - (*noskipped)++; - return NULL; - } -} - -/* Returns an allocated string containing the ical item summary. */ -static char * -ical_read_summary (char *line) -{ - char *p, *summary; - - if ((p = strchr (line, ':')) != NULL) - { - p++; - summary = ical_unformat_line (p); - return summary; - } - else - return NULL; -} - -static void -ical_read_event (FILE *fdi, FILE *log, unsigned *noevents, unsigned *noapoints, - unsigned *noskipped, char *buf, char *lstore, - unsigned *lineno) -{ - const int ITEMLINE = *lineno; - const struct string endevent = STRING_BUILD ("END:VEVENT"); - const struct string summary = STRING_BUILD ("SUMMARY"); - const struct string dtstart = STRING_BUILD ("DTSTART"); - const struct string dtend = STRING_BUILD ("DTEND"); - const struct string duration = STRING_BUILD ("DURATION"); - const struct string rrule = STRING_BUILD ("RRULE"); - const struct string exdate = STRING_BUILD ("EXDATE"); - const struct string alarm = STRING_BUILD ("BEGIN:VALARM"); - const struct string endalarm = STRING_BUILD ("END:VALARM"); - const struct string desc = STRING_BUILD ("DESCRIPTION"); - ical_vevent_e vevent_type; - char *p, buf_upper[BUFSIZ]; - struct { - llist_t exc; - ical_rpt_t *rpt; - char *mesg, *note; - long start, end, dur; - int has_alarm; - } vevent; - int skip_alarm; - - vevent_type = UNDEFINED; - bzero (&vevent, sizeof vevent); - skip_alarm = 0; - while (ical_readline (fdi, buf, lstore, lineno)) - { - strncpy (buf_upper, buf, BUFSIZ); - buf_upper[BUFSIZ - 1] = '\0'; - str_toupper (buf_upper); - - if (skip_alarm) - { - /* Need to skip VALARM properties because some keywords could - interfere, such as DURATION, SUMMARY,.. */ - if (strncmp (buf_upper, endalarm.str, endalarm.len) == 0) - skip_alarm = 0; - continue; - } - if (strncmp (buf_upper, endevent.str, endevent.len) == 0) - { - if (vevent.mesg) - { - if (vevent.rpt && vevent.rpt->count) - vevent.rpt->until = ical_compute_rpt_until (vevent.start, - vevent.rpt); - - switch (vevent_type) - { - case APPOINTMENT: - if (vevent.start == 0) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("appointment has no start time.")); - goto cleanup; - } - if (vevent.dur == 0) - { - if (vevent.end == 0) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("could not compute duration " - "(no end time).")); - goto cleanup; - } - else if (vevent.start == vevent.end) - { - vevent_type = EVENT; - vevent.end = 0L; - ical_store_event (vevent.mesg, vevent.note, - vevent.start, vevent.end, - vevent.rpt, &vevent.exc); - (*noevents)++; - return; - } - else - { - vevent.dur = vevent.end - vevent.start; - if (vevent.dur < 0) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("item has a negative duration.")); - goto cleanup; - } - } - } - ical_store_apoint (vevent.mesg, vevent.note, vevent.start, - vevent.dur, vevent.rpt, &vevent.exc, - vevent.has_alarm); - (*noapoints)++; - break; - case EVENT: - if (vevent.start == 0) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("event date is not defined.")); - goto cleanup; - } - ical_store_event (vevent.mesg, vevent.note, vevent.start, - vevent.end, vevent.rpt, &vevent.exc); - (*noevents)++; - break; - case UNDEFINED: - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("item could not be identified.")); - goto cleanup; - break; - } - } - else - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("could not retrieve item summary.")); - goto cleanup; - } - return; - } - else - { - if (strncmp (buf_upper, dtstart.str, dtstart.len) == 0) - { - if ((p = strchr (buf, ':')) != NULL) - vevent.start = ical_datetime2long (++p, &vevent_type); - if (!vevent.start) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("could not retrieve event start time.")); - goto cleanup; - } - } - else if (strncmp (buf_upper, dtend.str, dtend.len) == 0) - { - if ((p = strchr (buf, ':')) != NULL) - vevent.end = ical_datetime2long (++p, &vevent_type); - if (!vevent.end) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("could not retrieve event end time.")); - goto cleanup; - } - } - else if (strncmp (buf_upper, duration.str, duration.len) == 0) - { - if ((vevent.dur = ical_dur2long (buf)) <= 0) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("item duration malformed.")); - goto cleanup; - } - } - else if (strncmp (buf_upper, rrule.str, rrule.len) == 0) - { - vevent.rpt = ical_read_rrule (log, buf, noskipped, ITEMLINE); - } - else if (strncmp (buf_upper, exdate.str, exdate.len) == 0) - { - ical_read_exdate (&vevent.exc, log, buf, noskipped, ITEMLINE); - } - else if (strncmp (buf_upper, summary.str, summary.len) == 0) - { - vevent.mesg = ical_read_summary (buf); - } - else if (strncmp (buf_upper, alarm.str, alarm.len) == 0) - { - skip_alarm = 1; - vevent.has_alarm = 1; - } - else if (strncmp (buf_upper, desc.str, desc.len) == 0) - { - vevent.note = ical_read_note (buf, noskipped, ICAL_VEVENT, - ITEMLINE, log); - } - } - } - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("The ical file seems to be malformed. " - "The end of item was not found.")); - -cleanup: - - if (vevent.note) - mem_free (vevent.note); - if (vevent.mesg) - mem_free (vevent.mesg); - if (vevent.rpt) - mem_free (vevent.rpt); - LLIST_FREE (&vevent.exc); - (*noskipped)++; -} - -static void -ical_read_todo (FILE *fdi, FILE *log, unsigned *notodos, unsigned *noskipped, - char *buf, char *lstore, unsigned *lineno) -{ - const struct string endtodo = STRING_BUILD ("END:VTODO"); - const struct string summary = STRING_BUILD ("SUMMARY"); - const struct string alarm = STRING_BUILD ("BEGIN:VALARM"); - const struct string endalarm = STRING_BUILD ("END:VALARM"); - const struct string desc = STRING_BUILD ("DESCRIPTION"); - const int LOWEST = 9; - const int ITEMLINE = *lineno; - char buf_upper[BUFSIZ]; - struct { - char *mesg, *note; - int has_priority, priority; - } vtodo; - int skip_alarm; - - bzero (&vtodo, sizeof vtodo); - skip_alarm = 0; - while (ical_readline (fdi, buf, lstore, lineno)) - { - strncpy (buf_upper, buf, BUFSIZ); - buf_upper[BUFSIZ - 1] = '\0'; - str_toupper (buf_upper); - if (skip_alarm) - { - /* Need to skip VALARM properties because some keywords could - interfere, such as DURATION, SUMMARY,.. */ - if (strncmp (buf_upper, endalarm.str, endalarm.len) == 0) - skip_alarm = 0; - continue; - } - if (strncmp (buf_upper, endtodo.str, endtodo.len) == 0) - { - if (!vtodo.has_priority) - vtodo.priority = LOWEST; - if (vtodo.mesg) - { - ical_store_todo (vtodo.priority, vtodo.mesg, vtodo.note); - (*notodos)++; - } - else - { - ical_log (log, ICAL_VTODO, ITEMLINE, - _("could not retrieve item summary.")); - goto cleanup; - } - return; - } - else - { - int tmpint; - - if (sscanf (buf_upper, "PRIORITY:%d", &tmpint) == 1) - { - if (tmpint <= 9 && tmpint >= 1) - { - vtodo.priority = tmpint; - vtodo.has_priority = 1; - } - else - { - ical_log (log, ICAL_VTODO, ITEMLINE, - _("item priority is not acceptable " - "(must be between 1 and 9).")); - vtodo.priority = LOWEST; - } - } - else if (strncmp (buf_upper, summary.str, summary.len) == 0) - { - vtodo.mesg = ical_read_summary (buf); - } - else if (strncmp (buf_upper, alarm.str, alarm.len) == 0) - { - skip_alarm = 1; - } - else if (strncmp (buf_upper, desc.str, desc.len) == 0) - { - vtodo.note = ical_read_note (buf, noskipped, ICAL_VTODO, - ITEMLINE, log); - } - } - } - ical_log (log, ICAL_VTODO, ITEMLINE, - _("The ical file seems to be malformed. " - "The end of item was not found.")); - -cleanup: - - if (vtodo.note) - mem_free (vtodo.note); - if (vtodo.mesg) - mem_free (vtodo.mesg); - (*noskipped)++; -} - -static FILE * -get_import_stream (enum export_type type) +static FILE *get_import_stream(enum export_type type) { FILE *stream; char *stream_name; - char *ask_fname = _("Enter the file name to import data from:"); - char *wrong_file = - _("The file cannot be accessed, please enter another file name."); - char *press_enter = _("Press [ENTER] to continue."); + 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); - bzero (stream_name, BUFSIZ); - while (stream == NULL) - { - status_mesg (ask_fname, ""); - cancel = updatestring (win[STA].p, &stream_name, 0, 1); - if (cancel) - { - mem_free (stream_name); - return NULL; - } - stream = fopen (stream_name, "r"); - if (stream == NULL) - { - status_mesg (wrong_file, press_enter); - (void)wgetch (win[STA].p); - } + 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) { + mem_free(stream_name); + return NULL; } - mem_free (stream_name); + stream = fopen(stream_name, "r"); + if (stream == NULL) { + status_mesg(wrong_file, press_enter); + wgetch(win[STA].p); + } + } + mem_free(stream_name); return stream; } @@ -2715,229 +993,182 @@ get_import_stream (enum export_type type) * A temporary log file is created in /tmp to store the import process report, * and is cleared at the end. */ -void -io_import_data (enum import_type type, struct conf *conf, char *stream_name) +void io_import_data(enum import_type type, const char *stream_name) { - const struct string vevent = STRING_BUILD ("BEGIN:VEVENT"); - const struct string vtodo = STRING_BUILD ("BEGIN:VTODO"); - char *proc_report = _("Import process report: %04d lines read "); - char *lines_stats = - _("%d apps / %d events / %d todos / %d skipped "); - char *lines_stats_interactive = - _("%d apps / %d events / %d todos / %d skipped ([ENTER] to continue)"); - char buf[BUFSIZ], lstore[BUFSIZ]; + const char *proc_report = _("Import process report: %04d lines read "); + char stats_str[4][BUFSIZ]; FILE *stream = NULL; struct io_file *log; - float ical_version; struct { unsigned events, apoints, todos, lines, skipped; } stats; - EXIT_IF (type < 0 || type >= IO_IMPORT_NBTYPES, _("unknown import type")); - switch (ui_mode) - { - case UI_CMDLINE: - stream = fopen (stream_name, "r"); - EXIT_IF (stream == NULL, - _("FATAL ERROR: the input file cannot be accessed, " - "Aborting...")); - break; - case UI_CURSES: - stream = get_import_stream (type); - break; - default: - EXIT (_("FATAL ERROR: wrong import mode")); - /* NOTREACHED */ - } + EXIT_IF(type < 0 || type >= IO_IMPORT_NBTYPES, _("unknown import type")); + switch (ui_mode) { + case UI_CMDLINE: + stream = fopen(stream_name, "r"); + EXIT_IF(stream == NULL, + _("FATAL ERROR: the input file cannot be accessed, " + "Aborting...")); + break; + case UI_CURSES: + stream = get_import_stream(type); + break; + default: + EXIT(_("FATAL ERROR: wrong import mode")); + /* NOTREACHED */ + } if (stream == NULL) return; - bzero (&stats, sizeof stats); - ical_readline_init (stream, buf, lstore, &stats.lines); - ical_version = ical_chk_header (stream, buf, lstore, &stats.lines); - RETURN_IF (ical_version < 0, - _("Warning: ical header malformed or wrong version number. " - "Aborting...")); - - log = io_log_init (); - if (log == NULL) - { - if (stream != stdin) - file_close (stream, __FILE_POS__); - return; - } - ical_log_init (log->fd, ical_version); - - while (ical_readline (stream, buf, lstore, &stats.lines)) - { - stats.lines++; - str_toupper (buf); - if (strncmp (buf, vevent.str, vevent.len) == 0) - { - ical_read_event (stream, log->fd, &stats.events, &stats.apoints, - &stats.skipped, buf, lstore, &stats.lines); - } - else if (strncmp (buf, vtodo.str, vtodo.len) == 0) - { - ical_read_todo (stream, log->fd, &stats.todos, &stats.skipped, - buf, lstore, &stats.lines); - } - } - if (stream != stdin) - file_close (stream, __FILE_POS__); + memset(&stats, 0, sizeof stats); - /* Update the number of todo items. */ - todo_set_nb (todo_nb () + stats.todos); + log = io_log_init(); + if (log == NULL) { + if (stream != stdin) + file_close(stream, __FILE_POS__); + return; + } - if (ui_mode == UI_CURSES && !conf->skip_system_dialogs) - { - char read[BUFSIZ], stat[BUFSIZ]; + if (type == IO_IMPORT_ICAL) + ical_import_data(stream, log->fd, &stats.events, &stats.apoints, + &stats.todos, &stats.lines, &stats.skipped); - (void)snprintf (read, BUFSIZ, proc_report, stats.lines); - (void)snprintf (stat, BUFSIZ, lines_stats_interactive, stats.apoints, - stats.events, stats.todos, stats.skipped); - status_mesg (read, stat); - (void)wgetch (win[STA].p); - } - else if (ui_mode == UI_CMDLINE) - { - printf (proc_report, stats.lines); - printf ("\n"); - printf (lines_stats, stats.apoints, stats.events, stats.todos, - stats.skipped); - printf ("\n"); - } + if (stream != stdin) + file_close(stream, __FILE_POS__); + + snprintf(stats_str[0], BUFSIZ, + ngettext("%d app", "%d apps", stats.apoints), stats.apoints); + snprintf(stats_str[1], BUFSIZ, + ngettext("%d event", "%d events", stats.events), stats.events); + snprintf(stats_str[2], BUFSIZ, + ngettext("%d todo", "%d todos", stats.todos), stats.todos); + snprintf(stats_str[3], BUFSIZ, _("%d skipped"), stats.skipped); + + /* Update the number of todo items. */ + todo_set_nb(todo_nb() + stats.todos); + + if (ui_mode == UI_CURSES && conf.system_dialogs) { + char read[BUFSIZ], stat[BUFSIZ]; + + snprintf(read, BUFSIZ, proc_report, stats.lines); + snprintf(stat, BUFSIZ, "%s / %s / %s / %s (%s)", stats_str[0], + stats_str[1], stats_str[2], stats_str[3], + _("Press [ENTER] to continue")); + status_mesg(read, stat); + wgetch(win[STA].p); + } else if (ui_mode == UI_CMDLINE) { + printf(proc_report, stats.lines); + printf("\n%s / %s / %s / %s\n", stats_str[0], stats_str[1], + stats_str[2], stats_str[3]); + } /* User has the choice to look at the log file if some items could not be imported. - */ - file_close (log->fd, __FILE_POS__); - if (stats.skipped > 0) - { - char *view_log = _("Some items could not be imported, see log file ?"); + */ + file_close(log->fd, __FILE_POS__); + if (stats.skipped > 0) { + const char *view_log = + _("Some items could not be imported, see log file ?"); - io_log_display (log, view_log, conf->pager); - } - io_log_free (log); + io_log_display(log, view_log, conf.pager); + } + io_log_free(log); } -struct io_file * -io_log_init (void) +struct io_file *io_log_init(void) { char logprefix[BUFSIZ]; char *logname; struct io_file *log; - snprintf (logprefix, BUFSIZ, "%s/calcurse_log.", get_tempdir ()); - logname = new_tempfile (logprefix, NOTESIZ); - RETVAL_IF (logname == NULL, 0, - _("Warning: could not create temporary log file, Aborting...")); - log = mem_malloc (sizeof (struct io_file)); - RETVAL_IF (log == NULL, 0, - _("Warning: could not open temporary log file, Aborting...")); - (void)snprintf (log->name, sizeof (log->name), "%s%s", logprefix, logname); - mem_free (logname); - log->fd = fopen (log->name, "w"); - if (log->fd == NULL) - { - ERROR_MSG (_("Warning: could not open temporary log file, Aborting...")); - mem_free (log); - return 0; - } + snprintf(logprefix, BUFSIZ, "%s/calcurse_log.", get_tempdir()); + logname = new_tempfile(logprefix, TMPEXTSIZ); + RETVAL_IF(logname == NULL, 0, + _("Warning: could not create temporary log file, Aborting...")); + log = mem_malloc(sizeof(struct io_file)); + RETVAL_IF(log == NULL, 0, + _("Warning: could not open temporary log file, Aborting...")); + snprintf(log->name, sizeof(log->name), "%s%s", logprefix, logname); + mem_free(logname); + log->fd = fopen(log->name, "w"); + if (log->fd == NULL) { + ERROR_MSG(_("Warning: could not open temporary log file, Aborting...")); + mem_free(log); + return 0; + } return log; } -void -io_log_print (struct io_file *log, int line, char *msg) +void io_log_print(struct io_file *log, int line, const char *msg) { if (log && log->fd) - (void)fprintf (log->fd, "line %d: %s\n", line, msg); + fprintf(log->fd, "line %d: %s\n", line, msg); } -void -io_log_display (struct io_file *log, char *msg, char *pager) +void io_log_display(struct io_file *log, const char *msg, const char *pager) { - char *choices = "[y/n] "; int ans; - RETURN_IF (log == NULL, _("No log file to display!")); - if (ui_mode == UI_CMDLINE) - { - printf ("\n%s %s", msg, choices); - ans = fgetc (stdin); - if (ans == 'y') - { - char cmd[BUFSIZ]; - - (void)snprintf (cmd, BUFSIZ, "%s %s", pager, log->name); - (void)system (cmd); - } - } - else - { - status_mesg (msg, choices); - do - { - ans = wgetch (win[STA].p); - if (ans == 'y') - { - wins_launch_external (log->name, pager); - } - } - while (ans != 'y' && ans != 'n'); - wins_erase_status_bar (); + 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') { + const char *arg[] = { pager, log->name, NULL }; + int pid; + + if ((pid = fork_exec(NULL, NULL, pager, arg))) + child_wait(NULL, NULL, pid); } + } else { + if (status_ask_bool(msg) == 1) + wins_launch_external(log->name, pager); + wins_erase_status_bar(); + } } -void -io_log_free (struct io_file *log) +void io_log_free(struct io_file *log) { if (!log) return; - EXIT_IF (unlink (log->name) != 0, - _("Warning: could not erase temporary log file %s, Aborting..."), - log->name); - mem_free (log); + EXIT_IF(unlink(log->name) != 0, + _("Warning: could not erase temporary log file %s, Aborting..."), + log->name); + mem_free(log); } static pthread_t io_t_psave; /* Thread used to periodically save data. */ -static void * -io_psave_thread (void *arg) +static void *io_psave_thread(void *arg) { - struct conf *config; int delay; - config = (struct conf *)arg; - delay = config->periodic_save; - EXIT_IF (delay < 0, _("Invalid delay")); + delay = conf.periodic_save; + EXIT_IF(delay < 0, _("Invalid delay")); - for (;;) - { - (void)sleep (delay * MININSEC); - io_save_cal (config, IO_SAVE_DISPLAY_MARK); - } + for (;;) { + sleep(delay * MININSEC); + io_save_cal(IO_SAVE_DISPLAY_MARK); + } } /* Launch the thread which handles periodic saves. */ -void -io_start_psave_thread (struct conf *conf) +void io_start_psave_thread(void) { - pthread_create (&io_t_psave, NULL, io_psave_thread, (void *)conf); + pthread_create(&io_t_psave, NULL, io_psave_thread, NULL); } /* Stop periodic data saves. */ -void -io_stop_psave_thread (void) +void io_stop_psave_thread(void) { - if (io_t_psave) - { - pthread_cancel (io_t_psave); - pthread_join (io_t_psave, NULL); - } + if (io_t_psave) { + pthread_cancel(io_t_psave); + pthread_join(io_t_psave, NULL); + } } /* @@ -2951,49 +1182,40 @@ io_stop_psave_thread (void) * Note: When creating the lock file, the interactive mode is not initialized * yet. */ -void -io_set_lock (void) +void io_set_lock(void) { - FILE *lock = fopen (path_cpid, "r"); + FILE *lock = fopen(path_cpid, "r"); int pid; - if (lock != NULL) - { - /* If there is a lock file, check whether the process exists. */ - if (fscanf(lock, "%d", &pid) == 1) - { - fclose(lock); - if (kill(pid, 0) != 0 && errno == ESRCH) - lock = NULL; - } - else - fclose(lock); - } - - if (lock != NULL) - { - (void)fprintf (stderr, - _("\nWARNING: it seems that another calcurse instance is " - "already running.\n" - "If this is not the case, please remove the following " - "lock file: \n\"%s\"\n" - "and restart calcurse.\n"), path_cpid); - exit (EXIT_FAILURE); - } - else - { - if (!io_dump_pid (path_cpid)) - EXIT (_("FATAL ERROR: could not create %s: %s\n"), - path_cpid, strerror (errno)); - } + if (lock != NULL) { + /* If there is a lock file, check whether the process exists. */ + if (fscanf(lock, "%d", &pid) == 1) { + fclose(lock); + if (kill(pid, 0) != 0 && errno == ESRCH) + lock = NULL; + } else + fclose(lock); + } + + if (lock != NULL) { + fprintf(stderr, + _("\nWARNING: it seems that another calcurse instance is " + "already running.\n" + "If this is not the case, please remove the following " + "lock file: \n\"%s\"\n" "and restart calcurse.\n"), path_cpid); + exit(EXIT_FAILURE); + } else { + if (!io_dump_pid(path_cpid)) + EXIT(_("FATAL ERROR: could not create %s: %s\n"), + path_cpid, strerror(errno)); + } } /* * Create a new file and write the process pid inside (used to create a simple * lock for example). Overwrite already existing files. */ -unsigned -io_dump_pid (char *file) +unsigned io_dump_pid(char *file) { pid_t pid; FILE *fp; @@ -3001,10 +1223,9 @@ io_dump_pid (char *file) if (!file) return 0; - pid = getpid (); - if (!(fp = fopen (file, "w")) - || fprintf (fp, "%ld\n", (long)pid) < 0 - || fclose (fp) != 0) + pid = getpid(); + if (!(fp = fopen(file, "w")) + || fprintf(fp, "%ld\n", (long)pid) < 0 || fclose(fp) != 0) return 0; return 1; @@ -3015,8 +1236,7 @@ io_dump_pid (char *file) * io_dump_pid (). * If no file was found, return 0. */ -unsigned -io_get_pid (char *file) +unsigned io_get_pid(char *file) { FILE *fp; unsigned pid; @@ -3024,13 +1244,13 @@ io_get_pid (char *file) if (!file) return 0; - if ((fp = fopen (file, "r")) == NULL) + if ((fp = fopen(file, "r")) == NULL) return 0; - if (fscanf (fp, "%u", &pid) != 1) + if (fscanf(fp, "%u", &pid) != 1) return 0; - (void)fclose (fp); + fclose(fp); return pid; } @@ -3038,24 +1258,48 @@ io_get_pid (char *file) /* * Check whether a file is empty. */ -int -io_file_is_empty (char *file) +int io_file_is_empty(char *file) { FILE *fp; - if (file && (fp = fopen (file, "r"))) - { - if ((fgetc (fp) == '\n' && fgetc (fp) == EOF) || feof (fp)) - { - fclose (fp); - return 1; - } - else - { - fclose (fp); - return 0; - } + if (file && (fp = fopen(file, "r"))) { + if ((fgetc(fp) == '\n' && fgetc(fp) == EOF) || feof(fp)) { + fclose(fp); + return 1; + } else { + fclose(fp); + return 0; } + } return -1; } + +/* + * Copy an existing file to a new location. + */ +int io_file_cp(const char *src, const char *dst) +{ + FILE *fp_src, *fp_dst; + char *buffer[BUFSIZ]; + unsigned int bytes_read; + + if (!(fp_src = fopen(src, "rb"))) + return 0; + if (!(fp_dst = fopen(dst, "wb"))) + return 0; + + while (!feof(fp_src)) { + bytes_read = fread(buffer, 1, BUFSIZ, fp_src); + if (bytes_read > 0) { + if (fwrite(buffer, 1, bytes_read, fp_dst) != bytes_read) + return 0; + } else + return 0; + } + + fclose(fp_dst); + fclose(fp_src); + + return 1; +} @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -39,20 +39,14 @@ #include "calcurse.h" -#define MAXKEYVAL KEY_MAX /* ncurses defines KEY_MAX as maximum key value */ +#define MAXKEYVAL KEY_MAX /* ncurses defines KEY_MAX as maximum key value */ struct keydef_s { - char *label; - char *binding; + const char *label; + const char *binding; }; -struct key_str_s { - char *str; - struct key_str_s *next; -}; - -static struct key_str_s *keys[NBKEYS]; - +static llist_t keys[NBKEYS]; static enum key actions[MAXKEYVAL]; static struct keydef_s keydef[NBKEYS] = { @@ -81,16 +75,17 @@ static struct keydef_s keydef[NBKEYS] = { {"generic-scroll-up", "C-p"}, {"generic-goto-today", "C-g"}, - {"move-right", "l L"}, - {"move-left", "h H"}, - {"move-down", "j J"}, - {"move-up", "k K"}, + {"move-right", "l L RGT"}, + {"move-left", "h H LFT"}, + {"move-down", "j J DWN"}, + {"move-up", "k K UP"}, {"start-of-week", "0"}, {"end-of-week", "$"}, {"add-item", "a A"}, {"del-item", "d D"}, {"edit-item", "e E"}, {"view-item", "v V"}, + {"pipe-item", "|"}, {"flag-item", "!"}, {"repeat", "r R"}, {"edit-note", "n N"}, @@ -99,92 +94,80 @@ static struct keydef_s keydef[NBKEYS] = { {"lower-priority", "-"}, }; -static void -dump_intro (FILE *fd) +static void dump_intro(FILE * fd) { - char *intro = - _("#\n" - "# Calcurse keys configuration file\n#\n" - "# This file sets the keybindings used by Calcurse.\n" - "# Lines beginning with \"#\" are comments, and ignored by Calcurse.\n" - "# To assign a keybinding to an action, this file must contain a line\n" - "# with the following syntax:\n#\n" - "# ACTION KEY1 KEY2 ... KEYn\n#\n" - "# Where ACTION is what will be performed when KEY1, KEY2, ..., or KEYn\n" - "# will be pressed.\n" - "#\n" - "# To define bindings which use the CONTROL key, prefix the key with " - "'C-'.\n" - "# The escape, space bar and horizontal Tab key can be specified using\n" - "# the 'ESC', 'SPC' and 'TAB' keyword, respectively.\n" - "# Arrow keys can also be specified with the UP, DWN, LFT, RGT keywords.\n" - "# Last, Home and End keys can be assigned using 'KEY_HOME' and 'KEY_END'\n" - "# keywords." - "\n#\n" - "# A description of what each ACTION keyword is used for is available\n" - "# from calcurse online configuration menu.\n"); - - (void)fprintf (fd, "%s\n", intro); + const char *intro = + _("#\n" + "# Calcurse keys configuration file\n#\n" + "# This file sets the keybindings used by Calcurse.\n" + "# Lines beginning with \"#\" are comments, and ignored by Calcurse.\n" + "# To assign a keybinding to an action, this file must contain a line\n" + "# with the following syntax:\n#\n" + "# ACTION KEY1 KEY2 ... KEYn\n#\n" + "# Where ACTION is what will be performed when KEY1, KEY2, ..., or KEYn\n" + "# will be pressed.\n" + "#\n" + "# To define bindings which use the CONTROL key, prefix the key with " + "'C-'.\n" + "# The escape, space bar and horizontal Tab key can be specified using\n" + "# the 'ESC', 'SPC' and 'TAB' keyword, respectively.\n" + "# Arrow keys can also be specified with the UP, DWN, LFT, RGT keywords.\n" + "# Last, Home and End keys can be assigned using 'KEY_HOME' and 'KEY_END'\n" + "# keywords." + "\n#\n" + "# A description of what each ACTION keyword is used for is available\n" + "# from calcurse online configuration menu.\n"); + + fprintf(fd, "%s\n", intro); } -void -keys_init (void) +void keys_init(void) { int i; for (i = 0; i < MAXKEYVAL; i++) actions[i] = KEY_UNDEF; - bzero (keys, NBKEYS); + for (i = 0; i < NBKEYS; i++) + LLIST_INIT(&keys[i]); } -void -keys_free (void) +static void key_free(char *s) { - struct key_str_s *o, **i; - int key; - - for (key = 0; key < NBKEYS; key++) - { - if (keys[key] == NULL) - continue; - - i = &keys[key]; - while (*i) - { - o = *i; - *i = o->next; - mem_free (o->str); - mem_free (o); - } - } + mem_free(s); } -void -keys_dump_defaults (char *file) +void keys_free(void) +{ + int i; + + for (i = 0; i < NBKEYS; i++) { + LLIST_FREE_INNER(&keys[i], key_free); + LLIST_FREE(&keys[i]); + } +} + +void keys_dump_defaults(char *file) { FILE *fd; int i; - fd = fopen (file, "w"); - EXIT_IF (fd == NULL, _("FATAL ERROR: could not create default keys file.")); + fd = fopen(file, "w"); + EXIT_IF(fd == NULL, _("FATAL ERROR: could not create default keys file.")); - dump_intro (fd); + dump_intro(fd); for (i = 0; i < NBKEYS; i++) - (void)fprintf (fd, "%s %s\n", keydef[i].label, keydef[i].binding); - file_close (fd, __FILE_POS__); + fprintf(fd, "%s %s\n", keydef[i].label, keydef[i].binding); + file_close(fd, __FILE_POS__); } -char * -keys_get_label (enum key key) +const char *keys_get_label(enum key key) { - EXIT_IF (key < 0 || key > NBKEYS, - _("FATAL ERROR: key value out of bounds")); + EXIT_IF(key < 0 || key > NBKEYS, _("FATAL ERROR: key value out of bounds")); return keydef[key].label; } -enum key -keys_get_action (int pressed) +enum key keys_get_action(int pressed) { if (pressed < 0 || pressed > MAXKEYVAL) return -1; @@ -192,461 +175,391 @@ keys_get_action (int pressed) return actions[pressed]; } -enum key -keys_getch (WINDOW *win) +enum key keys_getch(WINDOW * win, int *count) { - int ch; - - ch = wgetch (win); - switch (ch) - { - case KEY_RESIZE: - return KEY_RESIZE; - default: - return keys_get_action (ch); + int ch = '0'; + + if (count) { + *count = 0; + do { + *count = *count * 10 + ch - '0'; + ch = wgetch(win); } + while ((ch == '0' && *count > 0) || (ch >= '1' && ch <= '9')); + + if (*count == 0) + *count = 1; + } else + ch = wgetch(win); + + switch (ch) { + case KEY_RESIZE: + return KEY_RESIZE; + default: + return keys_get_action(ch); + } } -static void -add_key_str (enum key action, int key) +static void add_key_str(enum key action, int key) { - struct key_str_s *new, **i; - if (action < 0 || action > NBKEYS) return; - new = mem_malloc (sizeof (struct key_str_s)); - new->str = mem_strdup (keys_int2str (key)); - new->next = NULL; - i = &keys[action]; - for (;;) - { - if (*i == NULL) - { - *i = new; - break; - } - else if ((*i)->next == NULL) - { - (*i)->next = new; - break; - } - i = &(*i)->next; - } + LLIST_ADD(&keys[action], mem_strdup(keys_int2str(key))); } -int -keys_assign_binding (int key, enum key action) +int keys_assign_binding(int key, enum key action) { if (key < 0 || key > MAXKEYVAL || actions[key] != KEY_UNDEF) return 1; - else - { - actions[key] = action; - add_key_str (action, key); - } + else { + actions[key] = action; + add_key_str(action, key); + } return 0; } -static void -del_key_str (enum key action, int key) +static void del_key_str(enum key action, int key) { - struct key_str_s *old, **i; + llist_item_t *i; char oldstr[BUFSIZ]; if (action < 0 || action > NBKEYS) return; - (void)strncpy (oldstr, keys_int2str (key), BUFSIZ); - for (i = &keys[action]; *i; i = &(*i)->next) - { - if (!strcmp ((*i)->str, oldstr)) - { - old = *i; - *i = old->next; - mem_free (old->str); - mem_free (old); - break; - } + strncpy(oldstr, keys_int2str(key), BUFSIZ); + + LLIST_FOREACH(&keys[action], i) { + if (strcmp(LLIST_GET_DATA(i), oldstr) == 0) { + LLIST_REMOVE(&keys[action], i); + return; } + } } -void -keys_remove_binding (int key, enum key action) +void keys_remove_binding(int key, enum key action) { - if (key < 0 || key > MAXKEYVAL) - return; - else - { - actions[key] = KEY_UNDEF; - del_key_str (action, key); - } + if (key >= 0 && key <= MAXKEYVAL) { + actions[key] = KEY_UNDEF; + del_key_str(action, key); + } } -int -keys_str2int (char *key) +int keys_str2int(const char *key) { - const struct string CONTROL_KEY = STRING_BUILD ("C-"); - const struct string TAB_KEY = STRING_BUILD ("TAB"); - const struct string SPACE_KEY = STRING_BUILD ("SPC"); - const struct string ESCAPE_KEY = STRING_BUILD ("ESC"); - const struct string CURSES_KEY_UP = STRING_BUILD ("UP"); - const struct string CURSES_KEY_DOWN = STRING_BUILD ("DWN"); - const struct string CURSES_KEY_LEFT = STRING_BUILD ("LFT"); - const struct string CURSES_KEY_RIGHT = STRING_BUILD ("RGT"); - const struct string CURSES_KEY_HOME = STRING_BUILD ("KEY_HOME"); - const struct string CURSES_KEY_END = STRING_BUILD ("KEY_END"); + const char CONTROL_KEY[] = "C-"; + const char TAB_KEY[] = "TAB"; + const char SPACE_KEY[] = "SPC"; + const char ESCAPE_KEY[] = "ESC"; + const char CURSES_KEY_UP[] = "UP"; + const char CURSES_KEY_DOWN[] = "DWN"; + const char CURSES_KEY_LEFT[] = "LFT"; + const char CURSES_KEY_RIGHT[] = "RGT"; + const char CURSES_KEY_HOME[] = "KEY_HOME"; + const char CURSES_KEY_END[] = "KEY_END"; if (!key) return -1; - if (strlen (key) == 1) + if (strlen(key) == 1) return (int)key[0]; - else - { - if (key[0] == '^') - return CTRL ((int)key[1]); - else if (!strncmp (key, CONTROL_KEY.str, CONTROL_KEY.len)) - return CTRL ((int)key[CONTROL_KEY.len]); - else if (!strncmp (key, TAB_KEY.str, TAB_KEY.len)) - return TAB; - else if (!strncmp (key, ESCAPE_KEY.str, ESCAPE_KEY.len)) - return ESCAPE; - else if (!strncmp (key, SPACE_KEY.str, SPACE_KEY.len)) - return SPACE; - else if (!strncmp (key, CURSES_KEY_UP.str, CURSES_KEY_UP.len)) - return KEY_UP; - else if (!strncmp (key, CURSES_KEY_DOWN.str, CURSES_KEY_DOWN.len)) - return KEY_DOWN; - else if (!strncmp (key, CURSES_KEY_LEFT.str, CURSES_KEY_LEFT.len)) - return KEY_LEFT; - else if (!strncmp (key, CURSES_KEY_RIGHT.str, CURSES_KEY_RIGHT.len)) - return KEY_RIGHT; - else if (!strncmp (key, CURSES_KEY_HOME.str, CURSES_KEY_HOME.len)) - return KEY_HOME; - else if (!strncmp (key, CURSES_KEY_END.str, CURSES_KEY_END.len)) - return KEY_END; - else - return -1; - } + else { + if (key[0] == '^') + return CTRL((int)key[1]); + else if (!strncmp(key, CONTROL_KEY, sizeof(CONTROL_KEY) - 1)) + return CTRL((int)key[sizeof(CONTROL_KEY) - 1]); + else if (!strcmp(key, TAB_KEY)) + return TAB; + else if (!strcmp(key, ESCAPE_KEY)) + return ESCAPE; + else if (!strcmp(key, SPACE_KEY)) + return SPACE; + else if (!strcmp(key, CURSES_KEY_UP)) + return KEY_UP; + else if (!strcmp(key, CURSES_KEY_DOWN)) + return KEY_DOWN; + else if (!strcmp(key, CURSES_KEY_LEFT)) + return KEY_LEFT; + else if (!strcmp(key, CURSES_KEY_RIGHT)) + return KEY_RIGHT; + else if (!strcmp(key, CURSES_KEY_HOME)) + return KEY_HOME; + else if (!strcmp(key, CURSES_KEY_END)) + return KEY_END; + else + return -1; + } } -char * -keys_int2str (int key) +const char *keys_int2str(int key) { - switch (key) - { - case TAB: - return "TAB"; - case SPACE: - return "SPC"; - case ESCAPE: - return "ESC"; - case KEY_UP: - return "UP"; - case KEY_DOWN: - return "DWN"; - case KEY_LEFT: - return "LFT"; - case KEY_RIGHT: - return "RGT"; - case KEY_HOME: - return "KEY_HOME"; - case KEY_END: - return "KEY_END"; - default: - return (char *)keyname (key); - } + switch (key) { + case TAB: + return "TAB"; + case SPACE: + return "SPC"; + case ESCAPE: + return "ESC"; + case KEY_UP: + return "UP"; + case KEY_DOWN: + return "DWN"; + case KEY_LEFT: + return "LFT"; + case KEY_RIGHT: + return "RGT"; + case KEY_HOME: + return "KEY_HOME"; + case KEY_END: + return "KEY_END"; + default: + return (char *)keyname(key); + } } -int -keys_action_count_keys (enum key action) +int keys_action_count_keys(enum key action) { - struct key_str_s *key; - int i; + llist_item_t *i; + int n = 0; - i = 0; - for (key = keys[action]; key; key = key->next) - i++; + LLIST_FOREACH(&keys[action], i) + n++; - return i; + return n; } -char * -keys_action_firstkey (enum key action) +const char *keys_action_firstkey(enum key action) { - return (keys[action] != NULL) ? keys[action]->str : "XXX"; + const char *s = LLIST_GET_DATA(LLIST_FIRST(&keys[action])); + return (s != NULL) ? s : "XXX"; } -char * -keys_action_nkey (enum key action, int keynum) +const char *keys_action_nkey(enum key action, int keynum) { - struct key_str_s *key; - int i; - - i = 0; - for (key = keys[action]; key; key = key->next) - { - if (i == keynum) - return key->str; - i++; - } - return (char *)0; + return LLIST_GET_DATA(LLIST_NTH(&keys[action], keynum)); } -char * -keys_action_allkeys (enum key action) +char *keys_action_allkeys(enum key action) { + llist_item_t *i; static char keystr[BUFSIZ]; - struct key_str_s *i; const char *CHAR_SPACE = " "; - if (keys[action] == NULL) + if (!LLIST_FIRST(&keys[action])) return NULL; + keystr[0] = '\0'; - for (i = keys[action]; i; i = i->next) - { - const int MAXLEN = sizeof (keystr) - 1 - strlen (keystr); - (void)strncat (keystr, i->str, MAXLEN - 1); - (void)strncat (keystr, CHAR_SPACE, 1); - } + LLIST_FOREACH(&keys[action], i) { + const int MAXLEN = sizeof(keystr) - 1 - strlen(keystr); + strncat(keystr, LLIST_GET_DATA(i), MAXLEN - 1); + strncat(keystr, CHAR_SPACE, 1); + } return keystr; } /* Need this to display keys properly inside status bar. */ -static char * -keys_format_label (char *key, int keylen) +static char *keys_format_label(char *key, int keylen) { static char fmtkey[BUFSIZ]; - const int len = strlen (key); - char *dot = "."; + const int len = strlen(key); + const char dot = '.'; int i; if (keylen > BUFSIZ) - return (char *)0; + return NULL; - bzero (fmtkey, sizeof (fmtkey)); + memset(fmtkey, 0, sizeof(fmtkey)); if (len == 0) - (void)snprintf (fmtkey, sizeof (fmtkey), "?"); - else if (len <= keylen) - { - for (i = 0; i < keylen - len; i++) - fmtkey[i] = ' '; - (void)strncat (fmtkey, key, keylen); - } - else - { - for (i = 0; i < keylen - 1; i++) - fmtkey[i] = key[i]; - (void)strncat (fmtkey, dot, strlen (dot)); - } + strncpy(fmtkey, "?", sizeof(fmtkey)); + else if (len <= keylen) { + for (i = 0; i < keylen - len; i++) + fmtkey[i] = ' '; + strncat(fmtkey, key, keylen); + } else { + for (i = 0; i < keylen - 1; i++) + fmtkey[i] = key[i]; + fmtkey[keylen - 1] = dot; + } return fmtkey; } void -keys_display_bindings_bar (WINDOW *win, struct binding **binding, int first_key, - int last_key) +keys_display_bindings_bar(WINDOW * win, struct binding *bindings[], int count, + int page_base, int page_size, struct binding *more) { - int i, j, cmdlen, space_between_cmds; - - /* Total length of a command. */ - cmdlen = KEYS_KEYLEN + 1 + KEYS_LABELEN; - space_between_cmds = floor (col / KEYS_CMDS_PER_LINE - cmdlen); - cmdlen += space_between_cmds; - - j = 0; - wins_erase_status_bar (); - for (i = first_key; i < last_key; i += 2) - { - char key[KEYS_KEYLEN + 1], *fmtkey; - const int KEY_POS = j * cmdlen; - const int LABEL_POS = j * cmdlen + KEYS_KEYLEN + 1; - - (void)strncpy (key, keys_action_firstkey (binding[i]->action), - KEYS_KEYLEN); - fmtkey = keys_format_label (key, KEYS_KEYLEN); - custom_apply_attr (win, ATTR_HIGHEST); - mvwprintw (win, 0, KEY_POS, fmtkey); - if (i + 1 != last_key) - { - (void)strncpy (key, keys_action_firstkey (binding[i + 1]->action), - KEYS_KEYLEN); - key[KEYS_KEYLEN] = 0; - fmtkey = keys_format_label (key, KEYS_KEYLEN); - mvwprintw (win, 1, KEY_POS, fmtkey); - } - custom_remove_attr (win, ATTR_HIGHEST); - mvwprintw (win, 0, LABEL_POS, binding[i]->label); - if (i + 1 != last_key) - mvwprintw (win, 1, LABEL_POS, binding[i + 1]->label); - j++; - } - wnoutrefresh (win); + /* Padding between two key bindings. */ + const int padding = (col * 2) / page_size - (KEYS_KEYLEN + KEYS_LABELEN + 1); + /* Total length of a key binding (including padding). */ + const int cmd_len = KEYS_KEYLEN + KEYS_LABELEN + 1 + padding; + + int i; + + wins_erase_status_bar(); + for (i = 0; i < page_size && page_base + i < count; i++) { + /* Location of key and label. */ + const int key_pos_x = (i / 2) * cmd_len; + const int key_pos_y = i % 2; + const int label_pos_x = key_pos_x + KEYS_KEYLEN + 1; + const int label_pos_y = key_pos_y; + + struct binding *binding; + char key[KEYS_KEYLEN + 1], *fmtkey; + + if (!more || i < page_size - 1 || page_base + i == count - 1) + binding = bindings[page_base + i]; + else + binding = more; + + strncpy(key, keys_action_firstkey(binding->action), KEYS_KEYLEN); + key[KEYS_KEYLEN] = '\0'; + fmtkey = keys_format_label(key, KEYS_KEYLEN); + + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, key_pos_y, key_pos_x, fmtkey); + custom_remove_attr(win, ATTR_HIGHEST); + mvwprintw(win, label_pos_y, label_pos_x, binding->label); + } + wnoutrefresh(win); } /* * Display information about the given key. * (could not add the keys descriptions to keydef variable, because of i18n). */ -void -keys_popup_info (enum key key) +void keys_popup_info(enum key key) { char *info[NBKEYS]; WINDOW *infowin; - info[KEY_GENERIC_CANCEL] = - _("Cancel the ongoing action."); - info[KEY_GENERIC_SELECT] = - _("Select the highlighted item."); + info[KEY_GENERIC_CANCEL] = _("Cancel the ongoing action."); + info[KEY_GENERIC_SELECT] = _("Select the highlighted item."); info[KEY_GENERIC_CREDITS] = - _("Print general information about calcurse's authors, license, etc."); + _("Print general information about calcurse's authors, license, etc."); info[KEY_GENERIC_HELP] = - _("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."); + _("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] = _("Help for `generic-cut`."); + info[KEY_GENERIC_PASTE] = _("Help for `generic-paste`."); info[KEY_GENERIC_CHANGE_VIEW] = - _("Select next panel in calcurse main screen."); - info[KEY_GENERIC_IMPORT] = - _("Import data from an external file."); - info[KEY_GENERIC_EXPORT] = - _("Export data to a new file format."); - info[KEY_GENERIC_GOTO] = - _("Select the day to go to."); + _("Select next panel in calcurse main screen."); + info[KEY_GENERIC_IMPORT] = _("Import data from an external file."); + info[KEY_GENERIC_EXPORT] = _("Export data to a new file format."); + info[KEY_GENERIC_GOTO] = _("Select the day to go to."); info[KEY_GENERIC_OTHER_CMD] = - _("Show next possible actions inside status bar."); - info[KEY_GENERIC_CONFIG_MENU] = - _("Enter the configuration menu."); - info[KEY_GENERIC_REDRAW] = - _("Redraw calcurse's screen."); + _("Show next possible actions inside status bar."); + info[KEY_GENERIC_CONFIG_MENU] = _("Enter the configuration menu."); + info[KEY_GENERIC_REDRAW] = _("Redraw calcurse's screen."); info[KEY_GENERIC_ADD_APPT] = - _("Add an appointment, whichever panel is currently selected."); + _("Add an appointment, whichever panel is currently selected."); info[KEY_GENERIC_ADD_TODO] = - _("Add a todo item, whichever panel is currently selected."); + _("Add a todo item, whichever panel is currently selected."); info[KEY_GENERIC_NEXT_DAY] = - _("Move to next day in calendar, whichever panel is currently selected."); + _("Move to next day in calendar, whichever panel is currently selected."); info[KEY_GENERIC_PREV_DAY] = - _("Move to previous day in calendar, whichever panel is currently " - "selected."); + _("Move to previous day in calendar, whichever panel is currently " + "selected."); info[KEY_GENERIC_NEXT_WEEK] = - _("Move to next week in calendar, whichever panel is currently selected."); + _ + ("Move to next week in calendar, whichever panel is currently selected."); info[KEY_GENERIC_PREV_WEEK] = - _("Move to previous week in calendar, whichever panel is currently " - "selected"); + _("Move to previous week in calendar, whichever panel is currently " + "selected"); info[KEY_GENERIC_SCROLL_DOWN] = - _("Scroll window down (e.g. when displaying text inside a popup window)."); + _ + ("Scroll window down (e.g. when displaying text inside a popup window)."); info[KEY_GENERIC_SCROLL_UP] = - _("Scroll window up (e.g. when displaying text inside a popup window)."); - info[KEY_GENERIC_GOTO_TODAY] = - _("Go to today, whichever panel is selected."); - info[KEY_MOVE_RIGHT] = - _("Move to the right."); - info[KEY_MOVE_LEFT] = - _("Move to the left."); - info[KEY_MOVE_DOWN] = - _("Move down."); - info[KEY_MOVE_UP] = - _("Move up."); + _("Scroll window up (e.g. when displaying text inside a popup window)."); + info[KEY_GENERIC_GOTO_TODAY] = _("Go to today, whichever panel is selected."); + info[KEY_MOVE_RIGHT] = _("Move to the right."); + info[KEY_MOVE_LEFT] = _("Move to the left."); + info[KEY_MOVE_DOWN] = _("Move down."); + info[KEY_MOVE_UP] = _("Move up."); info[KEY_START_OF_WEEK] = - _("Select the first day of the current week when inside the calendar " - "panel."); + _("Select the first day of the current week when inside the calendar " + "panel."); info[KEY_END_OF_WEEK] = - _("Select the last day of the current week when inside the calendar " - "panel."); - info[KEY_ADD_ITEM] = - _("Add an item to the currently selected panel."); - info[KEY_DEL_ITEM] = - _("Delete the currently selected item."); - info[KEY_EDIT_ITEM] = - _("Edit the currently seleted item."); + _("Select the last day of the current week when inside the calendar " + "panel."); + info[KEY_ADD_ITEM] = _("Add an item to the currently selected panel."); + info[KEY_DEL_ITEM] = _("Delete the currently selected item."); + info[KEY_EDIT_ITEM] = _("Edit the currently seleted item."); info[KEY_VIEW_ITEM] = - _("Display the currently selected item inside a popup window."); - info[KEY_FLAG_ITEM] = - _("Flag the currently selected item as important."); - info[KEY_REPEAT_ITEM] = - _("Repeat an item"); + _("Display the currently selected item inside a popup window."); + info[KEY_FLAG_ITEM] = _("Flag the currently selected item as important."); + info[KEY_REPEAT_ITEM] = _("Repeat an item"); + info[KEY_PIPE_ITEM] = + _("Pipe the currently selected item to an external program."); info[KEY_EDIT_NOTE] = - _("Attach (or edit if one exists) a note to the currently selected item"); + _("Attach (or edit if one exists) a note to the currently selected item"); info[KEY_VIEW_NOTE] = - _("View the note attached to the currently selected item."); - info[KEY_RAISE_PRIORITY] = - _("Raise a task priority inside the todo panel."); - info[KEY_LOWER_PRIORITY] = - _("Lower a task priority inside the todo panel."); + _("View the note attached to the currently selected item."); + info[KEY_RAISE_PRIORITY] = _("Raise a task priority inside the todo panel."); + info[KEY_LOWER_PRIORITY] = _("Lower a task priority inside the todo panel."); if (key < 0 || key > NBKEYS) return; #define WINROW 10 #define WINCOL (col - 4) - infowin = popup (WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2, - keydef[key].label, info[key], 1); - (void)keys_getch (infowin); - delwin (infowin); + infowin = popup(WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2, + keydef[key].label, info[key], 1); + keys_getch(infowin, NULL); + delwin(infowin); #undef WINROW #undef WINCOL } -void -keys_save_bindings (FILE *fd) +void keys_save_bindings(FILE * fd) { int i; - EXIT_IF (fd == NULL, _("FATAL ERROR: null file pointer.")); - dump_intro (fd); + EXIT_IF(fd == NULL, _("FATAL ERROR: null file pointer.")); + dump_intro(fd); for (i = 0; i < NBKEYS; i++) - (void)fprintf (fd, "%s %s\n", keydef[i].label, keys_action_allkeys (i)); + fprintf(fd, "%s %s\n", keydef[i].label, keys_action_allkeys(i)); } -int -keys_check_missing_bindings (void) +int keys_check_missing_bindings(void) { int i; - for (i = 0; i < NBKEYS; i++) - { - if (keys[i] == NULL) - return 1; - } + for (i = 0; i < NBKEYS; i++) { + if (!LLIST_FIRST(&keys[i])) + return 1; + } return 0; } -void -keys_fill_missing (void) +void keys_fill_missing(void) { int i; - for (i = 0; i < NBKEYS; i++) - { - if (keys[i] == NULL) - { - char *p, tmpbuf[BUFSIZ]; - - (void)strncpy (tmpbuf, keydef[i].binding, BUFSIZ); - p = tmpbuf; - for (;;) - { - char key_ch[BUFSIZ]; - - while (*p == ' ') - p++; - if (sscanf (p, "%s", key_ch) == 1) - { - int ch, used; - - ch = keys_str2int (key_ch); - used = keys_assign_binding (ch, i); - if (used) - WARN_MSG (_("When adding default key for \"%s\", " - "\"%s\" was already assigned!"), - keydef[i].label, key_ch); - p += strlen (key_ch) + 1; - } - else - break; - } - } + for (i = 0; i < NBKEYS; i++) { + if (!LLIST_FIRST(&keys[i])) { + char *p, tmpbuf[BUFSIZ]; + + strncpy(tmpbuf, keydef[i].binding, BUFSIZ); + p = tmpbuf; + for (;;) { + char key_ch[BUFSIZ]; + + while (*p == ' ') + p++; + if (sscanf(p, "%s", key_ch) == 1) { + int ch, used; + + ch = keys_str2int(key_ch); + used = keys_assign_binding(ch, i); + if (used) + WARN_MSG(_("When adding default key for \"%s\", " + "\"%s\" was already assigned!"), + keydef[i].label, key_ch); + p += strlen(key_ch) + 1; + } else + break; + } } + } } diff --git a/src/llist.c b/src/llist.c index eeded6b..847b795 100644 --- a/src/llist.c +++ b/src/llist.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -39,52 +39,47 @@ /* * Initialize a list. */ -void -llist_init (llist_t *l) +void llist_init(llist_t * l) { l->head = NULL; + l->tail = NULL; } /* * Free a list, but not the contained data. */ -void -llist_free (llist_t *l) +void llist_free(llist_t * l) { llist_item_t *i, *t; - for (i = l->head; i; i = t) - { - t = i->next; - mem_free (i); - } + for (i = l->head; i; i = t) { + t = i->next; + mem_free(i); + } l->head = NULL; + l->tail = NULL; } /* * Free the data contained in a list. */ -void -llist_free_inner (llist_t *l, llist_fn_free_t fn_free) +void llist_free_inner(llist_t * l, llist_fn_free_t fn_free) { llist_item_t *i; - for (i = l->head; i; i = i->next) - { - if (i->data) - { - fn_free(i->data); - i->data = NULL; - } + for (i = l->head; i; i = i->next) { + if (i->data) { + fn_free(i->data); + i->data = NULL; } + } } /* * Get the first item of a list. */ -llist_item_t * -llist_first (llist_t *l) +llist_item_t *llist_first(llist_t * l) { return l->head; } @@ -92,12 +87,14 @@ llist_first (llist_t *l) /* * Get the nth item of a list. */ -llist_item_t * -llist_nth (llist_t *l, int n) +llist_item_t *llist_nth(llist_t * l, int n) { llist_item_t *i; - for (i = l->head; i && n > 0; n--) + if (n < 0) + return NULL; + + for (i = l->head; i && n != 0; n--) i = i->next; return i; @@ -106,17 +103,28 @@ llist_nth (llist_t *l, int n) /* * Get the successor of a list item. */ -llist_item_t * -llist_next (llist_item_t *i) +llist_item_t *llist_next(llist_item_t * i) { return i ? i->next : NULL; } /* + * 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_fn_match_t fn_match) +{ + if (i && i->next && fn_match(i->next->data, data)) + return i->next; + else + return NULL; +} + +/* * Get the actual data of an item. */ -void * -llist_get_data (llist_item_t *i) +void *llist_get_data(llist_item_t * i) { return i ? i->data : NULL; } @@ -124,97 +132,88 @@ llist_get_data (llist_item_t *i) /* * Add an item at the end of a list. */ -void -llist_add (llist_t *l, void *data) +void llist_add(llist_t * l, void *data) { - llist_item_t *o = mem_malloc (sizeof (llist_item_t)); - llist_item_t *i; + llist_item_t *o = mem_malloc(sizeof(llist_item_t)); - if (o) - { - o->data = data; - o->next = NULL; - - if (!l->head) - l->head = o; - else - { - for (i = l->head; i->next; i = i->next) - ; - i->next = o; - } + if (o) { + o->data = data; + o->next = NULL; + + if (!l->head) + l->head = l->tail = o; + else { + l->tail->next = o; + l->tail = o; } + } } /* * Add an item to a sorted list. */ -void -llist_add_sorted (llist_t *l, void *data, llist_fn_cmp_t fn_cmp) +void llist_add_sorted(llist_t * l, void *data, llist_fn_cmp_t fn_cmp) { - llist_item_t *o = mem_malloc (sizeof (llist_item_t)); + llist_item_t *o = mem_malloc(sizeof(llist_item_t)); llist_item_t *i; - if (o) - { - o->data = data; - o->next = NULL; - - if (!l->head) - l->head = o; - else if (fn_cmp(o->data, l->head->data) < 0) - { - o->next = l->head; - l->head = o; - } - else - { - i = l->head; - while (i->next && fn_cmp(o->data, i->next->data) >= 0) - i = i->next; - o->next = i->next; - i->next = o; - } + if (o) { + o->data = data; + o->next = NULL; + + if (!l->head) + l->head = l->tail = o; + else if (fn_cmp(o->data, l->tail->data) >= 0) { + l->tail->next = o; + l->tail = o; + } else if (fn_cmp(o->data, l->head->data) < 0) { + o->next = l->head; + l->head = o; + } else { + i = l->head; + while (i->next && fn_cmp(o->data, i->next->data) >= 0) + i = i->next; + o->next = i->next; + i->next = o; } + } } /* * Remove an item from a list. */ -void -llist_remove (llist_t *l, llist_item_t *i) +void llist_remove(llist_t * l, llist_item_t * i) { llist_item_t *j = NULL; if (l->head && i == l->head) l->head = i->next; - else - { - for (j = l->head; j && j->next != i; j = j->next) - ; - } - - if (i) - { - if (j) - j->next = i->next; - mem_free (i); - } + else { + for (j = l->head; j && j->next != i; j = j->next) ; + } + + if (i) { + if (j) + j->next = i->next; + if (i == l->tail) + l->tail = j; + + mem_free(i); + } } /* * Find the first item matched by some filter callback. */ -llist_item_t * -llist_find_first (llist_t *l, long data, llist_fn_match_t fn_match) +llist_item_t *llist_find_first(llist_t * l, long 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; - } + for (i = l->head; i; i = i->next) { + if (fn_match(i->data, data)) + return i; + } return NULL; } @@ -222,18 +221,16 @@ llist_find_first (llist_t *l, long data, llist_fn_match_t fn_match) /* * Find the next item matched by some filter callback. */ -llist_item_t * -llist_find_next (llist_item_t *i, long data, llist_fn_match_t fn_match) +llist_item_t *llist_find_next(llist_item_t * i, long 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 (i) { + i = i->next; + for (; i; i = i->next) { + if (fn_match(i->data, data)) + return i; } + } return NULL; } @@ -241,16 +238,18 @@ llist_find_next (llist_item_t *i, long data, llist_fn_match_t fn_match) /* * Find the nth item matched by some filter callback. */ -llist_item_t * -llist_find_nth (llist_t *l, int n, long data, llist_fn_match_t fn_match) +llist_item_t *llist_find_nth(llist_t * l, int n, long 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) && (n-- == 0)) - return i; - } + if (n < 0) + return NULL; + + for (i = l->head; i; i = i->next) { + if (fn_match(i->data, data) && (n-- == 0)) + return i; + } return NULL; } diff --git a/src/llist.h b/src/llist.h index d7e4249..c795f37 100644 --- a/src/llist.h +++ b/src/llist.h @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -38,12 +38,13 @@ typedef struct llist_item llist_item_t; struct llist_item { struct llist_item *next; - void *data; + void *data; }; typedef struct llist llist_t; struct llist { struct llist_item *head; + struct llist_item *tail; }; typedef int (*llist_fn_cmp_t) (void *, void *); @@ -51,9 +52,9 @@ typedef int (*llist_fn_match_t) (void *, long); typedef void (*llist_fn_free_t) (void *); /* Initialization and deallocation. */ -void llist_init (llist_t *); -void llist_free (llist_t *); -void llist_free_inner (llist_t *, llist_fn_free_t); +void llist_init(llist_t *); +void llist_free(llist_t *); +void llist_free_inner(llist_t *, llist_fn_free_t); #define LLIST_INIT(l) llist_init(l) #define LLIST_FREE(l) llist_free(l) @@ -61,16 +62,19 @@ void llist_free_inner (llist_t *, llist_fn_free_t); llist_free_inner(l, (llist_fn_free_t)fn_free) /* Retrieving list items. */ -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_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_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); #define LLIST_FIRST(l) llist_first(l) #define LLIST_NTH(l, n) llist_nth(l, n) #define LLIST_NEXT(i) llist_next(i) +#define LLIST_NEXT_FILTER(i, data, fn_match) \ + llist_next_filter(i, data, (llist_fn_match_t)fn_match) #define LLIST_FIND_FIRST(l, data, fn_match) \ llist_find_first(l, data, (llist_fn_match_t)fn_match) #define LLIST_FIND_NEXT(i, data, fn_match) \ @@ -82,16 +86,19 @@ llist_item_t *llist_find_nth (llist_t *, int, long, llist_fn_match_t); #define LLIST_FIND_FOREACH(l, data, fn_match, i) \ for (i = LLIST_FIND_FIRST (l, data, fn_match); i; \ i = LLIST_FIND_NEXT (i, data, fn_match)) +#define LLIST_FIND_FOREACH_CONT(l, data, fn_match, i) \ + for (i = LLIST_FIND_FIRST (l, data, fn_match); i; \ + i = LLIST_NEXT_FILTER (i, data, fn_match)) /* Accessing list item data. */ -void *llist_get_data (llist_item_t *); +void *llist_get_data(llist_item_t *); #define LLIST_GET_DATA(i) llist_get_data(i) /* List manipulation. */ -void llist_add (llist_t *, void *); -void llist_add_sorted (llist_t *, void *, llist_fn_cmp_t); -void llist_remove (llist_t *, llist_item_t *); +void llist_add(llist_t *, void *); +void llist_add_sorted(llist_t *, void *, llist_fn_cmp_t); +void llist_remove(llist_t *, llist_item_t *); #define LLIST_ADD(l, data) llist_add(l, data) #define LLIST_ADD_SORTED(l, data, fn_cmp) \ diff --git a/src/llist_ts.h b/src/llist_ts.h index 0f90024..b452377 100644 --- a/src/llist_ts.h +++ b/src/llist_ts.h @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -37,8 +37,9 @@ /* Thread-safe linked lists. */ typedef struct llist_ts llist_ts_t; struct llist_ts { - llist_item_t *head; - pthread_mutex_t mutex; + llist_item_t *head; + llist_item_t *tail; + pthread_mutex_t mutex; }; /* Initialization and deallocation. */ @@ -63,6 +64,8 @@ struct llist_ts { #define LLIST_TS_FIRST(l_ts) llist_first ((llist_t *)l_ts) #define LLIST_TS_NTH(l_ts, n) llist_nth ((llist_t *)l_ts, n) #define LLIST_TS_NEXT(i) llist_next (i) +#define LLIST_TS_NEXT_FILTER(i, data, fn_match) \ + llist_next_filter (i, data, (llist_fn_match_t)fn_match) #define LLIST_TS_FIND_FIRST(l_ts, data, fn_match) \ llist_find_first ((llist_t *)l_ts, data, (llist_fn_match_t)fn_match) #define LLIST_TS_FIND_NEXT(i, data, fn_match) \ @@ -75,6 +78,9 @@ struct llist_ts { #define LLIST_TS_FIND_FOREACH(l_ts, data, fn_match, i) \ for (i = LLIST_TS_FIND_FIRST (l_ts, data, fn_match); i; \ i = LLIST_TS_FIND_NEXT (i, data, fn_match)) +#define LLIST_TS_FIND_FOREACH_CONT(l_ts, data, fn_match, i) \ + for (i = LLIST_TS_FIND_FIRST (l_ts, data, fn_match); i; \ + i = LLIST_TS_NEXT_FILTER (i, data, fn_match)) /* Accessing list item data. */ #define LLIST_TS_GET_DATA(i) llist_get_data (i) @@ -84,4 +90,3 @@ struct llist_ts { #define LLIST_TS_REMOVE(l_ts, i) llist_remove ((llist_t *)l_ts, i) #define LLIST_TS_ADD_SORTED(l_ts, data, fn_cmp) \ llist_add_sorted ((llist_t *)l_ts, data, (llist_fn_cmp_t)fn_cmp) - @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -41,6 +41,8 @@ #include "calcurse.h" +#ifdef CALCURSE_MEMORY_DEBUG + enum { BLK_STATE, BLK_SIZE, @@ -67,252 +69,233 @@ struct mem_stats { static struct mem_stats mstats; +#endif /* CALCURSE_MEMORY_DEBUG */ -static unsigned -stats_add_blk (size_t size, const char *pos) -{ - struct mem_blk *o, **i; - - o = malloc (sizeof (*o)); - EXIT_IF (o == NULL, _("could not allocate memory to store block info")); - - mstats.ncall++; - - o->pos = pos; - o->size = (unsigned)size; - o->next = 0; - - for (i = &mstats.blk; *i; i = &(*i)->next) - ; - o->id = mstats.ncall; - *i = o; - - return o->id; -} - -static void -stats_del_blk (unsigned id) -{ - struct mem_blk *o, **i; - - i = &mstats.blk; - for (o = mstats.blk; o; o = o->next) - { - if (o->id == id) - { - *i = o->next; - free (o); - return; - } - i = &o->next; - } - - EXIT (_("Block not found")); - /* NOTREACHED */ -} - -void * -xmalloc (size_t size) +void *xmalloc(size_t size) { void *p; - EXIT_IF (size == 0, _("xmalloc: zero size")); - p = malloc (size); - EXIT_IF (p == NULL, _("xmalloc: out of memory")); + EXIT_IF(size == 0, _("xmalloc: zero size")); + p = malloc(size); + EXIT_IF(p == NULL, _("xmalloc: out of memory")); return p; } -void * -xcalloc (size_t nmemb, size_t size) +void *xcalloc(size_t nmemb, size_t size) { void *p; - EXIT_IF (nmemb == 0 || size == 0, _("xcalloc: zero size")); - EXIT_IF (SIZE_MAX / nmemb < size, _("xcalloc: overflow")); - p = calloc (nmemb, size); - EXIT_IF (p == NULL, _("xcalloc: out of memory")); + EXIT_IF(nmemb == 0 || size == 0, _("xcalloc: zero size")); + EXIT_IF(SIZE_MAX / nmemb < size, _("xcalloc: overflow")); + p = calloc(nmemb, size); + EXIT_IF(p == NULL, _("xcalloc: out of memory")); return p; } -void * -xrealloc (void *ptr, size_t nmemb, size_t size) +void *xrealloc(void *ptr, size_t nmemb, size_t size) { void *new_ptr; size_t new_size; new_size = nmemb * size; - EXIT_IF (new_size == 0, _("xrealloc: zero size")); - EXIT_IF (SIZE_MAX / nmemb < size, _("xrealloc: overflow")); - new_ptr = realloc (ptr, new_size); - EXIT_IF (new_ptr == NULL, _("xrealloc: out of memory")); + EXIT_IF(new_size == 0, _("xrealloc: zero size")); + EXIT_IF(SIZE_MAX / nmemb < size, _("xrealloc: overflow")); + new_ptr = realloc(ptr, new_size); + EXIT_IF(new_ptr == NULL, _("xrealloc: out of memory")); return new_ptr; } -char * -xstrdup (const char *str) +char *xstrdup(const char *str) { size_t len; char *cp; - len = strlen (str) + 1; - cp = xmalloc (len); + len = strlen(str) + 1; + cp = xmalloc(len); + + return strncpy(cp, str, len); +} + +void xfree(void *p) +{ + EXIT_IF(p == NULL, _("xfree: null pointer")); + free(p); +} + +#ifdef CALCURSE_MEMORY_DEBUG + +static unsigned stats_add_blk(size_t size, const char *pos) +{ + struct mem_blk *o, **i; + + o = malloc(sizeof(*o)); + EXIT_IF(o == NULL, _("could not allocate memory to store block info")); + + mstats.ncall++; + + o->pos = pos; + o->size = (unsigned)size; + o->next = 0; + + for (i = &mstats.blk; *i; i = &(*i)->next) ; + o->id = mstats.ncall; + *i = o; - return strncpy (cp, str, len); + return o->id; } -void -xfree (void *p) +static void stats_del_blk(unsigned id) { - EXIT_IF (p == NULL, _("xfree: null pointer")); - free (p); + struct mem_blk *o, **i; + + i = &mstats.blk; + for (o = mstats.blk; o; o = o->next) { + if (o->id == id) { + *i = o->next; + free(o); + return; + } + i = &o->next; + } + + EXIT(_("Block not found")); + /* NOTREACHED */ } -void * -dbg_malloc (size_t size, const char *pos) +void *dbg_malloc(size_t size, const char *pos) { unsigned *buf; - if (size == 0) - return (void *)0; + if (size == 0) + return NULL; - size = EXTRA_SPACE + (size + sizeof (unsigned) - 1) / sizeof (unsigned); - buf = xmalloc (size * sizeof (unsigned)); + size = EXTRA_SPACE + (size + sizeof(unsigned) - 1) / sizeof(unsigned); + buf = xmalloc(size * sizeof(unsigned)); - buf[BLK_STATE] = MAGIC_ALLOC; /* state of the block */ - buf[BLK_SIZE] = size; /* size of the block */ - buf[BLK_ID] = stats_add_blk (size, pos); /* identify a block by its id */ - buf[size - 1] = buf[BLK_ID]; /* mark at end of block */ + buf[BLK_STATE] = MAGIC_ALLOC; /* state of the block */ + buf[BLK_SIZE] = size; /* size of the block */ + buf[BLK_ID] = stats_add_blk(size, pos); /* identify a block by its id */ + buf[size - 1] = buf[BLK_ID]; /* mark at end of block */ mstats.nalloc += size; return (void *)(buf + EXTRA_SPACE_START); } -void * -dbg_calloc (size_t nmemb, size_t size, const char *pos) +void *dbg_calloc(size_t nmemb, size_t size, const char *pos) { void *buf; if (!nmemb || !size) - return (void *)0; + return NULL; - EXIT_IF (nmemb > SIZE_MAX / size, _("overflow at %s"), pos); + EXIT_IF(nmemb > SIZE_MAX / size, _("overflow at %s"), pos); size *= nmemb; - if ((buf = dbg_malloc (size, pos)) == NULL) - return (void *)0; + if ((buf = dbg_malloc(size, pos)) == NULL) + return NULL; - bzero (buf, size); + memset(buf, 0, size); return buf; } -void * -dbg_realloc (void *ptr, size_t nmemb, size_t size, const char *pos) +void *dbg_realloc(void *ptr, size_t nmemb, size_t size, const char *pos) { unsigned *buf, old_size, new_size, cpy_size; if (ptr == NULL) - return (void *)0; + return NULL; - new_size = nmemb *size; + new_size = nmemb * size; if (new_size == 0) - return (void *)0; + return NULL; - EXIT_IF (nmemb > SIZE_MAX / size, _("overflow at %s"), pos); + EXIT_IF(nmemb > SIZE_MAX / size, _("overflow at %s"), pos); - if ((buf = dbg_malloc (new_size, pos)) == NULL) - return (void *)0; + if ((buf = dbg_malloc(new_size, pos)) == NULL) + return NULL; old_size = *((unsigned *)ptr - EXTRA_SPACE_START + BLK_SIZE); cpy_size = (old_size > new_size) ? new_size : old_size; - bcopy (ptr, buf, cpy_size); + memmove(buf, ptr, cpy_size); - mem_free (ptr); + mem_free(ptr); return (void *)buf; } -char * -dbg_strdup (const char *s, const char *pos) +char *dbg_strdup(const char *s, const char *pos) { size_t size; char *buf; if (s == NULL) - return (char *)0; + return NULL; - size = strlen (s); - if ((buf = dbg_malloc (size + 1, pos)) == NULL) - return (char *)0; + size = strlen(s); + if ((buf = dbg_malloc(size + 1, pos)) == NULL) + return NULL; - return strncpy (buf, s, size + 1); + return strncpy(buf, s, size + 1); } -void -dbg_free (void *ptr, const char *pos) +void dbg_free(void *ptr, const char *pos) { unsigned *buf, size; - EXIT_IF (ptr == NULL, _("dbg_free: null pointer at %s"), pos); + EXIT_IF(ptr == NULL, _("dbg_free: null pointer at %s"), pos); buf = (unsigned *)ptr - EXTRA_SPACE_START; size = buf[BLK_SIZE]; - EXIT_IF (buf[BLK_STATE] == MAGIC_FREE, - _("block seems already freed at %s"), pos); - EXIT_IF (buf[BLK_STATE] != MAGIC_ALLOC, - _("corrupt block header at %s"), pos); - EXIT_IF (buf[size - 1] != buf[BLK_ID], - _("corrupt block end at %s, (end = %u, should be %d)"), pos, - buf[size - 1], buf[BLK_ID]); + EXIT_IF(buf[BLK_STATE] == MAGIC_FREE, + _("block seems already freed at %s"), pos); + EXIT_IF(buf[BLK_STATE] != MAGIC_ALLOC, _("corrupt block header at %s"), pos); + EXIT_IF(buf[size - 1] != buf[BLK_ID], + _("corrupt block end at %s, (end = %u, should be %d)"), pos, + buf[size - 1], buf[BLK_ID]); buf[0] = MAGIC_FREE; - stats_del_blk (buf[BLK_ID]); + stats_del_blk(buf[BLK_ID]); - free (buf); + free(buf); mstats.nfree += size; } - -#ifdef CALCURSE_MEMORY_DEBUG - -static void -dump_block_info (struct mem_blk *blk) +static void dump_block_info(struct mem_blk *blk) { if (blk == NULL) return; - printf (_("---==== MEMORY BLOCK ====----------------\n")); - printf (_(" id: %u\n"), blk->id); - printf (_(" size: %u\n"), blk->size); - printf (_(" allocated in: %s\n"), blk->pos); - printf (_("-----------------------------------------\n")); + puts(_("---==== MEMORY BLOCK ====----------------\n")); + printf(_(" id: %u\n"), blk->id); + printf(_(" size: %u\n"), blk->size); + printf(_(" allocated in: %s\n"), blk->pos); + puts(_("-----------------------------------------\n")); } -void -mem_stats (void) +void mem_stats(void) { - printf ("\n"); - printf (_("+------------------------------+\n")); - printf (_("| calcurse memory usage report |\n")); - printf (_("+------------------------------+\n")); - printf (_(" number of calls: %u\n"), mstats.ncall); - printf (_(" allocated blocks: %u\n"), mstats.nalloc); - printf (_(" unfreed blocks: %u\n"), mstats.nalloc - mstats.nfree); - printf ("\n"); - - if (mstats.nfree < mstats.nalloc) - { - struct mem_blk *blk; - - for (blk = mstats.blk; blk; blk = blk->next) - dump_block_info (blk); - } + putchar('\n'); + puts(_("+------------------------------+\n")); + puts(_("| calcurse memory usage report |\n")); + puts(_("+------------------------------+\n")); + printf(_(" number of calls: %u\n"), mstats.ncall); + printf(_(" allocated blocks: %u\n"), mstats.nalloc); + printf(_(" unfreed blocks: %u\n"), mstats.nalloc - mstats.nfree); + putchar('\n'); + + if (mstats.nfree < mstats.nalloc) { + struct mem_blk *blk; + + for (blk = mstats.blk; blk; blk = blk->next) + dump_block_info(blk); + } } #endif /* CALCURSE_MEMORY_DEBUG */ diff --git a/src/note.c b/src/note.c new file mode 100644 index 0000000..d2f7ab2 --- /dev/null +++ b/src/note.c @@ -0,0 +1,235 @@ +/* + * 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 <unistd.h> +#include <dirent.h> + +#include "calcurse.h" +#include "sha1.h" + +struct note_gc_hash { + char *hash; + char buf[MAX_NOTESIZ + 1]; + HTABLE_ENTRY(note_gc_hash); +}; + +static void note_gc_extract_key(struct note_gc_hash *, const char **, int *); +static int note_gc_cmp(struct note_gc_hash *, struct note_gc_hash *); + +HTABLE_HEAD(htp, NOTE_GC_HSIZE, note_gc_hash); +HTABLE_PROTOTYPE(htp, note_gc_hash) + HTABLE_GENERATE(htp, note_gc_hash, note_gc_extract_key, note_gc_cmp) + +/* Create note file from a string and return a newly allocated string that + * contains its name. */ +char *generate_note(const char *str) +{ + char *sha1 = mem_malloc(SHA1_DIGESTLEN * 2 + 1); + char notepath[BUFSIZ]; + FILE *fp; + + sha1_digest(str, sha1); + snprintf(notepath, BUFSIZ, "%s%s", path_notes, sha1); + fp = fopen(notepath, "w"); + EXIT_IF(fp == NULL, _("Warning: could not open %s, Aborting..."), notepath); + fputs(str, fp); + file_close(fp, __FILE_POS__); + + return sha1; +} + +/* Edit a note with an external editor. */ +void edit_note(char **note, const char *editor) +{ + char tmppath[BUFSIZ]; + char *tmpext; + char notepath[BUFSIZ]; + char *sha1 = mem_malloc(SHA1_DIGESTLEN * 2 + 1); + FILE *fp; + + strncpy(tmppath, get_tempdir(), BUFSIZ); + strncat(tmppath, "/calcurse-note.", BUFSIZ - strlen(tmppath) - 1); + if ((tmpext = new_tempfile(tmppath, TMPEXTSIZ)) == NULL) + return; + strncat(tmppath, tmpext, BUFSIZ - strlen(tmppath) - 1); + mem_free(tmpext); + + if (*note != NULL) { + snprintf(notepath, BUFSIZ, "%s%s", path_notes, *note); + io_file_cp(notepath, tmppath); + } + + wins_launch_external(tmppath, editor); + + if (io_file_is_empty(tmppath) > 0) + erase_note(note); + else if ((fp = fopen(tmppath, "r"))) { + sha1_stream(fp, sha1); + fclose(fp); + *note = sha1; + + snprintf(notepath, BUFSIZ, "%s%s", path_notes, *note); + io_file_cp(tmppath, notepath); + } + + unlink(tmppath); +} + +/* View a note in an external pager. */ +void view_note(const char *note, const char *pager) +{ + char fullname[BUFSIZ]; + + if (note == NULL) + return; + snprintf(fullname, BUFSIZ, "%s%s", path_notes, note); + wins_launch_external(fullname, pager); +} + +/* Erase a note previously attached to an item. */ +void erase_note(char **note) +{ + if (*note == NULL) + return; + mem_free(*note); + *note = NULL; +} + +/* Read a serialized note file name from a stream and deserialize it. */ +void note_read(char *buffer, FILE * fp) +{ + int i; + + for (i = 0; i < MAX_NOTESIZ; i++) { + buffer[i] = getc(fp); + if (buffer[i] == ' ') { + buffer[i] = '\0'; + return; + } + } + + while (getc(fp) != ' ') ; + buffer[MAX_NOTESIZ] = '\0'; +} + +static void +note_gc_extract_key(struct note_gc_hash *data, const char **key, int *len) +{ + *key = data->hash; + *len = strlen(data->hash); +} + +static int note_gc_cmp(struct note_gc_hash *a, struct note_gc_hash *b) +{ + return strcmp(a->hash, b->hash); +} + +/* Spot and unlink unused note files. */ +void note_gc(void) +{ + struct htp gc_htable = HTABLE_INITIALIZER(&gc_htable); + struct note_gc_hash *hp; + DIR *dirp; + struct dirent *dp; + llist_item_t *i; + struct note_gc_hash tmph; + char notepath[BUFSIZ]; + + if (!(dirp = opendir(path_notes))) + return; + + /* Insert all note file names into a hash table. */ + do { + if ((dp = readdir(dirp)) && *(dp->d_name) != '.') { + hp = mem_malloc(sizeof(struct note_gc_hash)); + + strncpy(hp->buf, dp->d_name, MAX_NOTESIZ + 1); + hp->hash = hp->buf; + + HTABLE_INSERT(htp, &gc_htable, hp); + } + } + while (dp); + + closedir(dirp); + + /* Remove hashes that are actually in use. */ + LLIST_TS_FOREACH(&alist_p, i) { + struct apoint *apt = LLIST_GET_DATA(i); + if (apt->note) { + tmph.hash = apt->note; + free(HTABLE_REMOVE(htp, &gc_htable, &tmph)); + } + } + + LLIST_FOREACH(&eventlist, i) { + struct event *ev = LLIST_GET_DATA(i); + if (ev->note) { + tmph.hash = ev->note; + free(HTABLE_REMOVE(htp, &gc_htable, &tmph)); + } + } + + LLIST_TS_FOREACH(&recur_alist_p, i) { + struct recur_apoint *rapt = LLIST_GET_DATA(i); + if (rapt->note) { + tmph.hash = rapt->note; + free(HTABLE_REMOVE(htp, &gc_htable, &tmph)); + } + } + + LLIST_FOREACH(&recur_elist, i) { + struct recur_event *rev = LLIST_GET_DATA(i); + if (rev->note) { + tmph.hash = rev->note; + free(HTABLE_REMOVE(htp, &gc_htable, &tmph)); + } + } + + LLIST_FOREACH(&todolist, i) { + struct todo *todo = LLIST_GET_DATA(i); + if (todo->note) { + tmph.hash = todo->note; + free(HTABLE_REMOVE(htp, &gc_htable, &tmph)); + } + } + + /* Unlink unused note files. */ + HTABLE_FOREACH(hp, htp, &gc_htable) { + snprintf(notepath, BUFSIZ, "%s%s", path_notes, hp->hash); + unlink(notepath); + } +} diff --git a/src/notify.c b/src/notify.c index 3ed53bf..c746f49 100644 --- a/src/notify.c +++ b/src/notify.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -51,22 +51,21 @@ struct notify_vars { pthread_mutex_t mutex; }; -static struct notify_vars notify; -static struct notify_app notify_app; -static pthread_attr_t detached_thread_attr; -static pthread_t notify_t_main; +static struct notify_vars notify; +static struct notify_app notify_app; +static pthread_attr_t detached_thread_attr; +static pthread_t notify_t_main; /* * Return the number of seconds before next appointment * (0 if no upcoming appointment). */ -int -notify_time_left (void) +int notify_time_left(void) { time_t ntimer; int left; - ntimer = time (NULL); + ntimer = time(NULL); left = notify_app.time - ntimer; return left > 0 ? left : 0; @@ -76,11 +75,11 @@ notify_time_left (void) * Return 1 if the reminder was not sent already for the upcoming * appointment. */ -unsigned -notify_needs_reminder (void) +unsigned notify_needs_reminder(void) { if (notify_app.got_app - && (notify_app.state & APOINT_NOTIFY) + && (((notify_app.state & APOINT_NOTIFY) && !nbar.notify_all) || + (!(notify_app.state & APOINT_NOTIFY) && nbar.notify_all)) && !(notify_app.state & APOINT_NOTIFIED)) return 1; return 0; @@ -91,66 +90,62 @@ notify_needs_reminder (void) * Note: the mutex associated with this structure must be locked by the * caller! */ -void -notify_update_app (long start, char state, char *msg) +void notify_update_app(long start, char state, char *msg) { - notify_free_app (); + notify_free_app(); notify_app.got_app = 1; notify_app.time = start; notify_app.state = state; - notify_app.txt = mem_strdup (msg); + notify_app.txt = mem_strdup(msg); } /* Return 1 if we need to display the notify-bar, else 0. */ -int -notify_bar (void) +int notify_bar(void) { int display_bar = 0; - pthread_mutex_lock (&nbar.mutex); + pthread_mutex_lock(&nbar.mutex); display_bar = (nbar.show) ? 1 : 0; - pthread_mutex_unlock (&nbar.mutex); + pthread_mutex_unlock(&nbar.mutex); - return (display_bar); + return display_bar; } /* Initialize the nbar variable used to store notification options. */ -void -notify_init_vars (void) +void notify_init_vars(void) { - char *time_format = "%T"; - char *date_format = "%a %F"; - char *cmd = "printf '\\a'"; + const char *time_format = "%T"; + const char *date_format = "%a %F"; + const char *cmd = "printf '\\a'"; - pthread_mutex_init (&nbar.mutex, NULL); + pthread_mutex_init(&nbar.mutex, NULL); nbar.show = 1; nbar.cntdwn = 300; - (void)strncpy (nbar.datefmt, date_format, strlen (date_format) + 1); - (void)strncpy (nbar.timefmt, time_format, strlen (time_format) + 1); - (void)strncpy (nbar.cmd, cmd, strlen (cmd) + 1); + strncpy(nbar.datefmt, date_format, strlen(date_format) + 1); + strncpy(nbar.timefmt, time_format, strlen(time_format) + 1); + strncpy(nbar.cmd, cmd, strlen(cmd) + 1); - if ((nbar.shell = getenv ("SHELL")) == NULL) + if ((nbar.shell = getenv("SHELL")) == NULL) nbar.shell = "/bin/sh"; - (void)pthread_attr_init (&detached_thread_attr); - (void)pthread_attr_setdetachstate (&detached_thread_attr, - PTHREAD_CREATE_DETACHED); + nbar.notify_all = 0; + + pthread_attr_init(&detached_thread_attr); + pthread_attr_setdetachstate(&detached_thread_attr, PTHREAD_CREATE_DETACHED); } /* Extract the appointment file name from the complete file path. */ -static void -extract_aptsfile (void) +static void extract_aptsfile(void) { char *file; - file = strrchr (path_apts, '/'); + file = strrchr(path_apts, '/'); if (!file) notify.apts_file = path_apts; - else - { - notify.apts_file = file; - notify.apts_file++; - } + else { + notify.apts_file = file; + notify.apts_file++; + } } /* @@ -158,56 +153,50 @@ extract_aptsfile (void) * creating the notification window (l is the number of lines, c the * number of columns, y and x are its coordinates). */ -void -notify_init_bar (void) +void notify_init_bar(void) { - pthread_mutex_init (¬ify.mutex, NULL); - pthread_mutex_init (¬ify_app.mutex, NULL); + pthread_mutex_init(¬ify.mutex, NULL); + pthread_mutex_init(¬ify_app.mutex, NULL); notify_app.got_app = 0; notify_app.txt = 0; - notify.win = newwin (win[NOT].h, win[NOT].w, win[NOT].y, win[NOT].x); - extract_aptsfile (); + notify.win = newwin(win[NOT].h, win[NOT].w, win[NOT].y, win[NOT].x); + extract_aptsfile(); } /* * Free memory associated with the notify_app structure. */ -void -notify_free_app (void) +void notify_free_app(void) { notify_app.time = 0; notify_app.got_app = 0; notify_app.state = APOINT_NULL; if (notify_app.txt) - mem_free (notify_app.txt); + mem_free(notify_app.txt); notify_app.txt = 0; } /* Stop the notify-bar main thread. */ -void -notify_stop_main_thread (void) +void notify_stop_main_thread(void) { - if (notify_t_main) - { - pthread_cancel (notify_t_main); - pthread_join (notify_t_main, NULL); - } + if (notify_t_main) { + pthread_cancel(notify_t_main); + pthread_join(notify_t_main, NULL); + } } /* * The calcurse window geometry has changed so we need to reset the * notification window. */ -void -notify_reinit_bar (void) +void notify_reinit_bar(void) { - delwin (notify.win); - notify.win = newwin (win[NOT].h, win[NOT].w, win[NOT].y, win[NOT].x); + delwin(notify.win); + notify.win = newwin(win[NOT].h, win[NOT].w, win[NOT].y, win[NOT].x); } /* Launch user defined command as a notification. */ -unsigned -notify_launch_cmd (void) +unsigned notify_launch_cmd(void) { int pid; @@ -216,23 +205,19 @@ notify_launch_cmd (void) notify_app.state |= APOINT_NOTIFIED; - pid = fork (); + pid = fork(); - if (pid < 0) - { - ERROR_MSG (_("error while launching command: could not fork")); - return 0; - } - else if (pid == 0) - { - /* Child: launch user defined command */ - if (execlp (nbar.shell, nbar.shell, "-c", nbar.cmd, (char *)0) < 0) - { - ERROR_MSG (_("error while launching command")); - _exit (1); - } - _exit (0); + if (pid < 0) { + ERROR_MSG(_("error while launching command: could not fork")); + return 0; + } else if (pid == 0) { + /* Child: launch user defined command */ + if (execlp(nbar.shell, nbar.shell, "-c", nbar.cmd, NULL) < 0) { + ERROR_MSG(_("error while launching command")); + _exit(1); } + _exit(0); + } return 1; } @@ -241,8 +226,7 @@ notify_launch_cmd (void) * Update the notification bar. This is useful when changing color theme * for example. */ -void -notify_update_bar (void) +void notify_update_bar(void) { const int space = 3; int file_pos, date_pos, app_pos, txt_max_len, too_long = 0; @@ -250,82 +234,77 @@ notify_update_bar (void) char buf[BUFSIZ]; date_pos = space; - pthread_mutex_lock (¬ify.mutex); + pthread_mutex_lock(¬ify.mutex); - file_pos = strlen (notify.date) + strlen (notify.time) + 7 + 2 * space; - app_pos = file_pos + strlen (notify.apts_file) + 2 + space; + file_pos = strlen(notify.date) + strlen(notify.time) + 7 + 2 * space; + app_pos = file_pos + strlen(notify.apts_file) + 2 + space; txt_max_len = col - (app_pos + 12 + space); - custom_apply_attr (notify.win, ATTR_HIGHEST); - wattron (notify.win, A_UNDERLINE | A_REVERSE); - mvwhline (notify.win, 0, 0, ACS_HLINE, col); - mvwprintw (notify.win, 0, date_pos, "[ %s | %s ]", - notify.date, notify.time); - mvwprintw (notify.win, 0, file_pos, "(%s)", notify.apts_file); + custom_apply_attr(notify.win, ATTR_HIGHEST); + wattron(notify.win, A_UNDERLINE | A_REVERSE); + mvwhline(notify.win, 0, 0, ACS_HLINE, col); + mvwprintw(notify.win, 0, date_pos, "[ %s | %s ]", notify.date, notify.time); + mvwprintw(notify.win, 0, file_pos, "(%s)", notify.apts_file); + + pthread_mutex_lock(¬ify_app.mutex); + if (notify_app.got_app) { + if (strlen(notify_app.txt) > txt_max_len) { + int shrink_len; + + too_long = 1; + shrink_len = txt_max_len > 3 ? txt_max_len - 3 : 1; + strncpy(buf, notify_app.txt, shrink_len); + buf[shrink_len] = '\0'; + } + time_left = notify_time_left(); + if (time_left > 0) { + int hours_left, minutes_left; + + hours_left = (time_left / HOURINSEC); + minutes_left = (time_left - hours_left * HOURINSEC) / MININSEC; + pthread_mutex_lock(&nbar.mutex); + + if (time_left < nbar.cntdwn && + (((notify_app.state & APOINT_NOTIFY) && !nbar.notify_all) || + (!(notify_app.state & APOINT_NOTIFY) && nbar.notify_all))) + blinking = 1; + else + blinking = 0; - pthread_mutex_lock (¬ify_app.mutex); - if (notify_app.got_app) - { - if (strlen (notify_app.txt) > txt_max_len) - { - int shrink_len; - - too_long = 1; - shrink_len = txt_max_len > 3 ? txt_max_len - 3 : 1; - (void)strncpy (buf, notify_app.txt, shrink_len); - buf[shrink_len] = '\0'; - } - time_left = notify_time_left (); - if (time_left > 0) - { - int hours_left, minutes_left; - - hours_left = (time_left / HOURINSEC); - minutes_left = (time_left - hours_left * HOURINSEC) / MININSEC; - pthread_mutex_lock (&nbar.mutex); - - if (time_left < nbar.cntdwn && (notify_app.state & APOINT_NOTIFY)) - blinking = 1; - else - blinking = 0; - - if (blinking) - wattron (notify.win, A_BLINK); - if (too_long) - mvwprintw (notify.win, 0, app_pos, "> %02d:%02d :: %s.. <", - hours_left, minutes_left, buf); - else - mvwprintw (notify.win, 0, app_pos, "> %02d:%02d :: %s <", - hours_left, minutes_left, notify_app.txt); - if (blinking) - wattroff (notify.win, A_BLINK); - - if (blinking) - (void)notify_launch_cmd (); - pthread_mutex_unlock (&nbar.mutex); - } + if (blinking) + wattron(notify.win, A_BLINK); + if (too_long) + mvwprintw(notify.win, 0, app_pos, "> %02d:%02d :: %s.. <", + hours_left, minutes_left, buf); else - { - notify_app.got_app = 0; - pthread_mutex_unlock (¬ify_app.mutex); - pthread_mutex_unlock (¬ify.mutex); - notify_check_next_app (0); - return; - } + mvwprintw(notify.win, 0, app_pos, "> %02d:%02d :: %s <", + hours_left, minutes_left, notify_app.txt); + if (blinking) + wattroff(notify.win, A_BLINK); + + if (blinking) + notify_launch_cmd(); + pthread_mutex_unlock(&nbar.mutex); + } else { + notify_app.got_app = 0; + pthread_mutex_unlock(¬ify_app.mutex); + pthread_mutex_unlock(¬ify.mutex); + notify_check_next_app(0); + return; } - pthread_mutex_unlock (¬ify_app.mutex); + } + pthread_mutex_unlock(¬ify_app.mutex); - wattroff (notify.win, A_UNDERLINE | A_REVERSE); - custom_remove_attr (notify.win, ATTR_HIGHEST); - wins_wrefresh (notify.win); + wattroff(notify.win, A_UNDERLINE | A_REVERSE); + custom_remove_attr(notify.win, ATTR_HIGHEST); + wins_wrefresh(notify.win); - pthread_mutex_unlock (¬ify.mutex); + pthread_mutex_unlock(¬ify.mutex); } /* Update the notication bar content */ /* ARGSUSED0 */ -static void * -notify_main_thread (void *arg) +static void *notify_main_thread(void *arg) { const unsigned thread_sleep = 1; const unsigned check_app = MININSEC; @@ -336,49 +315,46 @@ notify_main_thread (void *arg) elapse = 0; - for (;;) - { - ntimer = time (NULL); - ntime = localtime (&ntimer); - pthread_mutex_lock (¬ify.mutex); - pthread_mutex_lock (&nbar.mutex); - strftime (notify.time, NOTIFY_FIELD_LENGTH, nbar.timefmt, ntime); - strftime (notify.date, NOTIFY_FIELD_LENGTH, nbar.datefmt, ntime); - pthread_mutex_unlock (&nbar.mutex); - pthread_mutex_unlock (¬ify.mutex); - notify_update_bar (); - psleep (thread_sleep); - elapse += thread_sleep; - if (elapse >= check_app) - { - elapse = 0; - pthread_mutex_lock (¬ify_app.mutex); - got_app = notify_app.got_app; - pthread_mutex_unlock (¬ify_app.mutex); - if (!got_app) - notify_check_next_app (0); - } + for (;;) { + ntimer = time(NULL); + ntime = localtime(&ntimer); + pthread_mutex_lock(¬ify.mutex); + pthread_mutex_lock(&nbar.mutex); + strftime(notify.time, NOTIFY_FIELD_LENGTH, nbar.timefmt, ntime); + strftime(notify.date, NOTIFY_FIELD_LENGTH, nbar.datefmt, ntime); + pthread_mutex_unlock(&nbar.mutex); + pthread_mutex_unlock(¬ify.mutex); + notify_update_bar(); + psleep(thread_sleep); + elapse += thread_sleep; + if (elapse >= check_app) { + elapse = 0; + pthread_mutex_lock(¬ify_app.mutex); + got_app = notify_app.got_app; + pthread_mutex_unlock(¬ify_app.mutex); + if (!got_app) + notify_check_next_app(0); } - pthread_exit ((void *) 0); + } + pthread_exit(NULL); } /* Fill the given structure with information about next appointment. */ -unsigned -notify_get_next (struct notify_app *a) +unsigned notify_get_next(struct notify_app *a) { time_t current_time; if (!a) return 0; - current_time = time (NULL); + current_time = time(NULL); a->time = current_time + DAYINSEC; a->got_app = 0; a->state = 0; - a->txt = (char *)0; - (void)recur_apoint_check_next (a, current_time, get_today ()); - (void)apoint_check_next (a, current_time); + a->txt = NULL; + recur_apoint_check_next(a, current_time, get_today()); + apoint_check_next(a, current_time); return 1; } @@ -387,191 +363,162 @@ notify_get_next (struct notify_app *a) * This is used for the daemon to check if we have an upcoming appointment or * not. */ -unsigned -notify_get_next_bkgd (void) +unsigned notify_get_next_bkgd(void) { struct notify_app a; - a.txt = (char *)0; - if (!notify_get_next (&a)) + a.txt = NULL; + if (!notify_get_next(&a)) return 0; - if (!a.got_app) - { - /* No next appointment, reset the previous notified one. */ - notify_app.got_app = 0; - return 1; - } - else - { - if (!notify_same_item (a.time)) - notify_update_app (a.time, a.state, a.txt); - } + if (!a.got_app) { + /* No next appointment, reset the previous notified one. */ + notify_app.got_app = 0; + return 1; + } else { + if (!notify_same_item(a.time)) + notify_update_app(a.time, a.state, a.txt); + } if (a.txt) - mem_free (a.txt); + mem_free(a.txt); return 1; } /* Return the description of next appointment to be notified. */ -char * -notify_app_txt (void) +char *notify_app_txt(void) { if (notify_app.got_app) return notify_app.txt; else - return (char *)0; + return NULL; } /* Look for the next appointment within the next 24 hours. */ /* ARGSUSED0 */ -static void * -notify_thread_app (void *arg) +static void *notify_thread_app(void *arg) { struct notify_app tmp_app; int force = (arg ? 1 : 0); - if (!notify_get_next (&tmp_app)) - pthread_exit ((void *)0); - - if (!tmp_app.got_app) - { - pthread_mutex_lock (¬ify_app.mutex); - notify_free_app (); - pthread_mutex_unlock (¬ify_app.mutex); - } - else - { - if (force || !notify_same_item (tmp_app.time)) - { - pthread_mutex_lock (¬ify_app.mutex); - notify_update_app (tmp_app.time, tmp_app.state, tmp_app.txt); - pthread_mutex_unlock (¬ify_app.mutex); - } + if (!notify_get_next(&tmp_app)) + pthread_exit(NULL); + + if (!tmp_app.got_app) { + pthread_mutex_lock(¬ify_app.mutex); + notify_free_app(); + pthread_mutex_unlock(¬ify_app.mutex); + } else { + if (force || !notify_same_item(tmp_app.time)) { + pthread_mutex_lock(¬ify_app.mutex); + notify_update_app(tmp_app.time, tmp_app.state, tmp_app.txt); + pthread_mutex_unlock(¬ify_app.mutex); } + } if (tmp_app.txt) - mem_free (tmp_app.txt); - notify_update_bar (); + mem_free(tmp_app.txt); + notify_update_bar(); - pthread_exit ((void *) 0); + pthread_exit(NULL); } /* Launch the thread notify_thread_app to look for next appointment. */ -void -notify_check_next_app (int force) +void notify_check_next_app(int force) { pthread_t notify_t_app; - void *arg = (force ? (void *)1 : (void *)0); + void *arg = (force ? (void *)1 : NULL); - pthread_create (¬ify_t_app, &detached_thread_attr, notify_thread_app, - arg); + pthread_create(¬ify_t_app, &detached_thread_attr, notify_thread_app, arg); return; } /* Check if the newly created appointment is to be notified. */ -void -notify_check_added (char *mesg, long start, char state) +void notify_check_added(char *mesg, long start, char state) { time_t current_time; int update_notify = 0; long gap; - current_time = time (NULL); - pthread_mutex_lock (¬ify_app.mutex); - if (!notify_app.got_app) - { - gap = start - current_time; - if (gap >= 0 && gap <= DAYINSEC) - update_notify = 1; - } - else if (start < notify_app.time && start >= current_time) - { + current_time = time(NULL); + pthread_mutex_lock(¬ify_app.mutex); + if (!notify_app.got_app) { + gap = start - current_time; + if (gap >= 0 && gap <= DAYINSEC) update_notify = 1; - } - else if (start == notify_app.time && state != notify_app.state) + } else if (start < notify_app.time && start >= current_time) { + update_notify = 1; + } else if (start == notify_app.time && state != notify_app.state) update_notify = 1; - if (update_notify) - { - notify_update_app (start, state, mesg); - } - pthread_mutex_unlock (¬ify_app.mutex); - notify_update_bar (); + if (update_notify) { + notify_update_app(start, state, mesg); + } + pthread_mutex_unlock(¬ify_app.mutex); + notify_update_bar(); } /* Check if the newly repeated appointment is to be notified. */ -void -notify_check_repeated (struct recur_apoint *i) +void notify_check_repeated(struct recur_apoint *i) { - long real_app_time; + unsigned real_app_time; int update_notify = 0; time_t current_time; - current_time = time (NULL); - pthread_mutex_lock (¬ify_app.mutex); - if ((real_app_time = recur_item_inday (i->start, &i->exc, i->rpt->type, - i->rpt->freq, i->rpt->until, - get_today ()))) - { - if (!notify_app.got_app) - { - if (real_app_time - current_time <= DAYINSEC) - update_notify = 1; - } - else if (real_app_time < notify_app.time && - real_app_time >= current_time) - { - update_notify = 1; - } - else if (real_app_time == notify_app.time && - i->state != notify_app.state) + current_time = time(NULL); + pthread_mutex_lock(¬ify_app.mutex); + if (recur_item_find_occurrence(i->start, i->dur, &i->exc, i->rpt->type, + i->rpt->freq, i->rpt->until, get_today(), + &real_app_time)) { + if (!notify_app.got_app) { + if (real_app_time - current_time <= DAYINSEC) update_notify = 1; - } - if (update_notify) - { - notify_update_app (real_app_time, i->state, i->mesg); - } - pthread_mutex_unlock (¬ify_app.mutex); - notify_update_bar (); + } else if (real_app_time < notify_app.time && real_app_time >= current_time) { + update_notify = 1; + } else if (real_app_time == notify_app.time && i->state != notify_app.state) + update_notify = 1; + } + if (update_notify) { + notify_update_app(real_app_time, i->state, i->mesg); + } + pthread_mutex_unlock(¬ify_app.mutex); + notify_update_bar(); } -int -notify_same_item (long time) +int notify_same_item(long time) { int same = 0; - pthread_mutex_lock (&(notify_app.mutex)); + pthread_mutex_lock(&(notify_app.mutex)); if (notify_app.got_app && notify_app.time == time) same = 1; - pthread_mutex_unlock (&(notify_app.mutex)); + pthread_mutex_unlock(&(notify_app.mutex)); return same; } -int -notify_same_recur_item (struct recur_apoint *i) +int notify_same_recur_item(struct recur_apoint *i) { int same = 0; - long item_start = 0; + unsigned item_start = 0; - item_start = recur_item_inday (i->start, &i->exc, i->rpt->type, - i->rpt->freq, i->rpt->until, get_today ()); - pthread_mutex_lock (¬ify_app.mutex); + recur_item_find_occurrence(i->start, i->dur, &i->exc, i->rpt->type, + i->rpt->freq, i->rpt->until, get_today(), + &item_start); + pthread_mutex_lock(¬ify_app.mutex); if (notify_app.got_app && item_start == notify_app.time) same = 1; - pthread_mutex_unlock (&(notify_app.mutex)); + pthread_mutex_unlock(&(notify_app.mutex)); return same; } /* Launch the notify-bar main thread. */ -void -notify_start_main_thread (void) +void notify_start_main_thread(void) { - pthread_create (¬ify_t_main, NULL, notify_main_thread, NULL); - notify_check_next_app (0); + pthread_create(¬ify_t_main, NULL, notify_main_thread, NULL); + notify_check_next_app(0); } /* @@ -580,255 +527,248 @@ notify_start_main_thread (void) * (either YES or NO), or an option holding a string value. */ static void -print_option (WINDOW *win, unsigned x, unsigned y, char *name, - char *valstr, unsigned valbool, char *desc, unsigned num) +print_option(WINDOW * win, unsigned x, unsigned y, char *name, + char *valstr, unsigned valbool, char *desc, unsigned num) { const int XOFF = 4; const int MAXCOL = col - 3; int x_opt, len; - x_opt = x + XOFF + strlen (name); - mvwprintw (win, y, x, "[%u] %s", num, name); - erase_window_part (win, x_opt, y, MAXCOL, y); - if ((len = strlen (valstr)) != 0) - { - unsigned maxlen; - - maxlen = MAXCOL - x_opt - 2; - custom_apply_attr (win, ATTR_HIGHEST); - if (len < maxlen) - mvwprintw (win, y, x_opt, "%s", valstr); - else - { - char buf[BUFSIZ]; - - (void)strncpy (buf, valstr, maxlen - 1); - buf[maxlen - 1] = '\0'; - mvwprintw (win, y, x_opt, "%s...", buf); - } - custom_remove_attr (win, ATTR_HIGHEST); + x_opt = x + XOFF + strlen(name); + mvwprintw(win, y, x, "[%u] %s", num, name); + erase_window_part(win, x_opt, y, MAXCOL, y); + if ((len = strlen(valstr)) != 0) { + unsigned maxlen; + + maxlen = MAXCOL - x_opt - 2; + custom_apply_attr(win, ATTR_HIGHEST); + if (len < maxlen) + mvwprintw(win, y, x_opt, "%s", valstr); + else { + char buf[BUFSIZ]; + + strncpy(buf, valstr, maxlen - 1); + buf[maxlen - 1] = '\0'; + mvwprintw(win, y, x_opt, "%s...", buf); } - else - print_bool_option_incolor (win, valbool, y, x_opt); - mvwprintw (win, y + 1, x, desc); + custom_remove_attr(win, ATTR_HIGHEST); + } else + print_bool_option_incolor(win, valbool, y, x_opt); + mvwprintw(win, y + 1, x, desc); } /* Print options related to the notify-bar. */ -static unsigned -print_config_options (WINDOW *optwin) +static unsigned print_config_options(WINDOW * optwin) { const int XORIG = 3; const int YORIG = 0; - const int YOFF = 3; + const int YOFF = 3; - enum - { SHOW, DATE, CLOCK, WARN, CMD, DMON, DMON_LOG, NB_OPT }; + enum { SHOW, DATE, CLOCK, WARN, CMD, NOTIFY_ALL, DMON, DMON_LOG, NB_OPT }; - struct opt_s - { - char *name; - char *desc; - char valstr[BUFSIZ]; - unsigned valnum; + struct opt_s { + char *name; + char *desc; + char valstr[BUFSIZ]; + unsigned valnum; } opt[NB_OPT]; int i; - opt[SHOW].name = _("notify-bar_show = "); + opt[SHOW].name = _("appearance.notifybar = "); opt[SHOW].desc = _("(if set to YES, notify-bar will be displayed)"); - opt[DATE].name = _("notify-bar_date = "); + opt[DATE].name = _("format.notifydate = "); opt[DATE].desc = _("(Format of the date to be displayed inside notify-bar)"); - opt[CLOCK].name = _("notify-bar_clock = "); + opt[CLOCK].name = _("format.notifytime = "); opt[CLOCK].desc = _("(Format of the time to be displayed inside notify-bar)"); - opt[WARN].name = _("notify-bar_warning = "); + opt[WARN].name = _("notification.warning = "); opt[WARN].desc = _("(Warn user if an appointment is within next " "'notify-bar_warning' seconds)"); - opt[CMD].name = _("notify-bar_command = "); + opt[CMD].name = _("notification.command = "); opt[CMD].desc = _("(Command used to notify user of an upcoming appointment)"); - opt[DMON].name = _("notify-daemon_enable = "); + opt[NOTIFY_ALL].name = _("notification.notifyall = "); + opt[NOTIFY_ALL].desc = + _("(Notify all appointments instead of flagged ones only)"); + + opt[DMON].name = _("daemon.enable = "); opt[DMON].desc = _("(Run in background to get notifications after exiting)"); - opt[DMON_LOG].name = _("notify-daemon_log = "); + opt[DMON_LOG].name = _("daemon.log = "); opt[DMON_LOG].desc = _("(Log activity when running in background)"); - pthread_mutex_lock (&nbar.mutex); + pthread_mutex_lock(&nbar.mutex); /* String value options */ - (void)strncpy (opt[DATE].valstr, nbar.datefmt, BUFSIZ); - (void)strncpy (opt[CLOCK].valstr, nbar.timefmt, BUFSIZ); - (void)snprintf (opt[WARN].valstr, BUFSIZ, "%d", nbar.cntdwn); - (void)strncpy (opt[CMD].valstr, nbar.cmd, BUFSIZ); + strncpy(opt[DATE].valstr, nbar.datefmt, BUFSIZ); + strncpy(opt[CLOCK].valstr, nbar.timefmt, BUFSIZ); + snprintf(opt[WARN].valstr, BUFSIZ, "%d", nbar.cntdwn); + strncpy(opt[CMD].valstr, nbar.cmd, BUFSIZ); /* Boolean options */ opt[SHOW].valnum = nbar.show; - pthread_mutex_unlock (&nbar.mutex); + opt[NOTIFY_ALL].valnum = nbar.notify_all; + pthread_mutex_unlock(&nbar.mutex); opt[DMON].valnum = dmon.enable; opt[DMON_LOG].valnum = dmon.log; - opt[SHOW].valstr[0] = opt[DMON].valstr[0] = opt[DMON_LOG].valstr[0] = '\0'; + opt[SHOW].valstr[0] = opt[NOTIFY_ALL].valstr[0] = opt[DMON].valstr[0] = + opt[DMON_LOG].valstr[0] = '\0'; - for (i = 0; i < NB_OPT; i++) - { - int y; + for (i = 0; i < NB_OPT; i++) { + int y; - y = YORIG + i * YOFF; - print_option (optwin, XORIG, y, opt[i].name, opt[i].valstr, - opt[i].valnum, opt[i].desc, i + 1); - } + y = YORIG + i * YOFF; + print_option(optwin, XORIG, y, opt[i].name, opt[i].valstr, + opt[i].valnum, opt[i].desc, i + 1); + } return YORIG + NB_OPT * YOFF; } -static void -reinit_conf_win (struct scrollwin *win) +static void reinit_conf_win(struct scrollwin *win) { unsigned first_line; first_line = win->first_visible_line; - wins_scrollwin_delete (win); - custom_set_swsiz (win); - wins_scrollwin_init (win); - wins_show (win->win.p, win->label); + wins_scrollwin_delete(win); + custom_set_swsiz(win); + wins_scrollwin_init(win); + wins_show(win->win.p, win->label); win->first_visible_line = first_line; } /* Notify-bar configuration. */ -void -notify_config_bar (void) +void notify_config_bar(void) { struct scrollwin cwin; char *buf; - char *number_str = - _("Enter an option number to change its value"); - char *keys = - _("(Press '^P' or '^N' to move up or down, 'Q' to quit)"); - char *date_str = - _("Enter the date format (see 'man 3 strftime' for possible formats) "); - char *time_str = - _("Enter the time format (see 'man 3 strftime' for possible formats) "); - char *count_str = - _("Enter the number of seconds (0 not to be warned before an appointment)"); - char *cmd_str = _("Enter the notification command "); + const char *number_str = _("Enter an option number to change its value"); + const char *keys = _("(Press '^P' or '^N' to move up or down, 'Q' to quit)"); + const char *date_str = + _("Enter the date format (see 'man 3 strftime' for possible formats) "); + const char *time_str = + _("Enter the time format (see 'man 3 strftime' for possible formats) "); + const char *count_str = + _ + ("Enter the number of seconds (0 not to be warned before an appointment)"); + const char *cmd_str = _("Enter the notification command "); int ch; - clear (); - custom_set_swsiz (&cwin); - (void)snprintf (cwin.label, BUFSIZ, _("notification options")); - wins_scrollwin_init (&cwin); - wins_show (cwin.win.p, cwin.label); - status_mesg (number_str, keys); - cwin.total_lines = print_config_options (cwin.pad.p); - wins_scrollwin_display (&cwin); - - buf = mem_malloc (BUFSIZ); - while ((ch = wgetch (win[STA].p)) != 'q') - { - buf[0] = '\0'; - - switch (ch) - { - case CTRL ('N'): - wins_scrollwin_down (&cwin, 1); - break; - case CTRL ('P'): - wins_scrollwin_up (&cwin, 1); - break; - case '1': - pthread_mutex_lock (&nbar.mutex); - nbar.show = !nbar.show; - pthread_mutex_unlock (&nbar.mutex); - if (notify_bar ()) - notify_start_main_thread (); - else - notify_stop_main_thread (); - wins_scrollwin_delete (&cwin); - reinit_conf_win (&cwin); - break; - case '2': - status_mesg (date_str, ""); - pthread_mutex_lock (&nbar.mutex); - (void)strncpy (buf, nbar.datefmt, strlen (nbar.datefmt) + 1); - pthread_mutex_unlock (&nbar.mutex); - if (updatestring (win[STA].p, &buf, 0, 1) == 0) - { - pthread_mutex_lock (&nbar.mutex); - (void)strncpy (nbar.datefmt, buf, strlen (buf) + 1); - pthread_mutex_unlock (&nbar.mutex); - } - break; - case '3': - status_mesg (time_str, ""); - pthread_mutex_lock (&nbar.mutex); - (void)strncpy (buf, nbar.timefmt, strlen (nbar.timefmt) + 1); - pthread_mutex_unlock (&nbar.mutex); - if (updatestring (win[STA].p, &buf, 0, 1) == 0) - { - pthread_mutex_lock (&nbar.mutex); - (void)strncpy (nbar.timefmt, buf, strlen (buf) + 1); - pthread_mutex_unlock (&nbar.mutex); - } - break; - case '4': - status_mesg (count_str, ""); - pthread_mutex_lock (&nbar.mutex); - snprintf (buf, BUFSIZ, "%d", nbar.cntdwn); - pthread_mutex_unlock (&nbar.mutex); - if (updatestring (win[STA].p, &buf, 0, 1) == 0 && - is_all_digit (buf) && atoi (buf) >= 0 && atoi (buf) <= DAYINSEC) - { - pthread_mutex_lock (&nbar.mutex); - nbar.cntdwn = atoi (buf); - pthread_mutex_unlock (&nbar.mutex); - } - break; - case '5': - status_mesg (cmd_str, ""); - pthread_mutex_lock (&nbar.mutex); - (void)strncpy (buf, nbar.cmd, strlen (nbar.cmd) + 1); - pthread_mutex_unlock (&nbar.mutex); - if (updatestring (win[STA].p, &buf, 0, 1) == 0) - { - pthread_mutex_lock (&nbar.mutex); - (void)strncpy (nbar.cmd, buf, strlen (buf) + 1); - pthread_mutex_unlock (&nbar.mutex); - } - break; - case '6': - dmon.enable = !dmon.enable; - break; - case '7': - dmon.log = !dmon.log; - break; - } - - if (resize) - { - resize = 0; - wins_get_config (); - wins_reset (); - reinit_conf_win (&cwin); - delwin (win[STA].p); - win[STA].p = newwin (win[STA].h, win[STA].w, win[STA].y, - win[STA].x); - keypad (win[STA].p, TRUE); - if (notify_bar ()) - { - notify_reinit_bar (); - notify_update_bar (); - } - clearok (curscr, TRUE); - } - - status_mesg (number_str, keys); - cwin.total_lines = print_config_options (cwin.pad.p); - wins_scrollwin_display (&cwin); + clear(); + custom_set_swsiz(&cwin); + cwin.label = _("notification options"); + wins_scrollwin_init(&cwin); + wins_show(cwin.win.p, cwin.label); + status_mesg(number_str, keys); + cwin.total_lines = print_config_options(cwin.pad.p); + wins_scrollwin_display(&cwin); + + buf = mem_malloc(BUFSIZ); + while ((ch = wgetch(win[STA].p)) != 'q') { + buf[0] = '\0'; + + switch (ch) { + case CTRL('N'): + wins_scrollwin_down(&cwin, 1); + break; + case CTRL('P'): + wins_scrollwin_up(&cwin, 1); + break; + case '1': + pthread_mutex_lock(&nbar.mutex); + nbar.show = !nbar.show; + pthread_mutex_unlock(&nbar.mutex); + if (notify_bar()) + notify_start_main_thread(); + else + notify_stop_main_thread(); + wins_scrollwin_delete(&cwin); + reinit_conf_win(&cwin); + break; + case '2': + status_mesg(date_str, ""); + pthread_mutex_lock(&nbar.mutex); + strncpy(buf, nbar.datefmt, strlen(nbar.datefmt) + 1); + pthread_mutex_unlock(&nbar.mutex); + if (updatestring(win[STA].p, &buf, 0, 1) == 0) { + pthread_mutex_lock(&nbar.mutex); + strncpy(nbar.datefmt, buf, strlen(buf) + 1); + pthread_mutex_unlock(&nbar.mutex); + } + break; + case '3': + status_mesg(time_str, ""); + pthread_mutex_lock(&nbar.mutex); + strncpy(buf, nbar.timefmt, strlen(nbar.timefmt) + 1); + pthread_mutex_unlock(&nbar.mutex); + if (updatestring(win[STA].p, &buf, 0, 1) == 0) { + pthread_mutex_lock(&nbar.mutex); + strncpy(nbar.timefmt, buf, strlen(buf) + 1); + pthread_mutex_unlock(&nbar.mutex); + } + break; + case '4': + status_mesg(count_str, ""); + pthread_mutex_lock(&nbar.mutex); + snprintf(buf, BUFSIZ, "%d", nbar.cntdwn); + pthread_mutex_unlock(&nbar.mutex); + if (updatestring(win[STA].p, &buf, 0, 1) == 0 && + is_all_digit(buf) && atoi(buf) >= 0 && atoi(buf) <= DAYINSEC) { + pthread_mutex_lock(&nbar.mutex); + nbar.cntdwn = atoi(buf); + pthread_mutex_unlock(&nbar.mutex); + } + break; + case '5': + status_mesg(cmd_str, ""); + pthread_mutex_lock(&nbar.mutex); + strncpy(buf, nbar.cmd, strlen(nbar.cmd) + 1); + pthread_mutex_unlock(&nbar.mutex); + if (updatestring(win[STA].p, &buf, 0, 1) == 0) { + pthread_mutex_lock(&nbar.mutex); + strncpy(nbar.cmd, buf, strlen(buf) + 1); + pthread_mutex_unlock(&nbar.mutex); + } + break; + case '6': + pthread_mutex_lock(&nbar.mutex); + nbar.notify_all = !nbar.notify_all; + pthread_mutex_unlock(&nbar.mutex); + notify_check_next_app(1); + break; + case '7': + dmon.enable = !dmon.enable; + break; + case '8': + dmon.log = !dmon.log; + break; + } + + if (resize) { + resize = 0; + wins_get_config(); + wins_reset(); + reinit_conf_win(&cwin); + delwin(win[STA].p); + win[STA].p = newwin(win[STA].h, win[STA].w, win[STA].y, win[STA].x); + keypad(win[STA].p, TRUE); + if (notify_bar()) { + notify_reinit_bar(); + notify_update_bar(); + } + clearok(curscr, TRUE); } - mem_free (buf); - wins_scrollwin_delete (&cwin); + + status_mesg(number_str, keys); + cwin.total_lines = print_config_options(cwin.pad.p); + wins_scrollwin_display(&cwin); + } + mem_free(buf); + wins_scrollwin_delete(&cwin); } diff --git a/src/pcal.c b/src/pcal.c new file mode 100644 index 0000000..c4f731d --- /dev/null +++ b/src/pcal.c @@ -0,0 +1,291 @@ +/* + * 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 <sys/types.h> + +#include "calcurse.h" + +/* Static functions used to add export functionalities. */ +static void pcal_export_header(FILE *); +static void pcal_export_recur_events(FILE *); +static void pcal_export_events(FILE *); +static void pcal_export_recur_apoints(FILE *); +static void pcal_export_apoints(FILE *); +static void pcal_export_todo(FILE *); +static void pcal_export_footer(FILE *); + +/* Type definition for callbacks to export functions. */ +typedef void (*cb_dump_t) (FILE *, long, long, char *); + +/* + * Travel through each occurence of an item, and execute the given callback + * (mainly used to export data). + */ +static void +foreach_date_dump(const long date_end, struct rpt *rpt, llist_t * exc, + long item_first_date, long item_dur, char *item_mesg, + cb_dump_t cb_dump, FILE * stream) +{ + long date, item_time; + struct tm lt; + time_t t; + + t = item_first_date; + lt = *localtime(&t); + lt.tm_hour = lt.tm_min = lt.tm_sec = 0; + lt.tm_isdst = -1; + date = mktime(<); + item_time = item_first_date - date; + + while (date <= date_end && date <= rpt->until) { + if (recur_item_inday(item_first_date, item_dur, exc, rpt->type, + rpt->freq, rpt->until, date)) { + (*cb_dump) (stream, date + item_time, item_dur, item_mesg); + } + switch (rpt->type) { + case RECUR_DAILY: + date = date_sec_change(date, 0, rpt->freq); + break; + case RECUR_WEEKLY: + date = date_sec_change(date, 0, rpt->freq * WEEKINDAYS); + break; + case RECUR_MONTHLY: + date = date_sec_change(date, rpt->freq, 0); + break; + case RECUR_YEARLY: + date = date_sec_change(date, rpt->freq * 12, 0); + break; + default: + EXIT(_("incoherent repetition type")); + /* NOTREACHED */ + break; + } + } +} + +static void pcal_export_header(FILE * stream) +{ + fputs("# calcurse pcal export\n", stream); + fputs("\n# =======\n# options\n# =======\n", stream); + fprintf(stream, "opt -A -K -l -m -F %s\n", + calendar_week_begins_on_monday()? "Monday" : "Sunday"); + fputs("# Display week number (i.e. 1-52) on every Monday\n", stream); + fprintf(stream, "all monday in all week %%w\n"); + fputc('\n', stream); +} + +static void pcal_export_footer(FILE * stream) +{ +} + +/* Format and dump event data to a pcal formatted file. */ +static void +pcal_dump_event(FILE * stream, long event_date, long event_dur, + char *event_mesg) +{ + char pcal_date[BUFSIZ]; + + date_sec2date_fmt(event_date, "%b %d", pcal_date); + fprintf(stream, "%s %s\n", pcal_date, event_mesg); +} + +/* Format and dump appointment data to a pcal formatted file. */ +static void +pcal_dump_apoint(FILE * stream, long apoint_date, long apoint_dur, + char *apoint_mesg) +{ + char pcal_date[BUFSIZ], pcal_beg[BUFSIZ], pcal_end[BUFSIZ]; + + date_sec2date_fmt(apoint_date, "%b %d", pcal_date); + date_sec2date_fmt(apoint_date, "%R", pcal_beg); + date_sec2date_fmt(apoint_date + apoint_dur, "%R", pcal_end); + fprintf(stream, "%s ", pcal_date); + fprintf(stream, "(%s -> %s) %s\n", pcal_beg, pcal_end, apoint_mesg); +} + +static void pcal_export_recur_events(FILE * stream) +{ + llist_item_t *i; + char pcal_date[BUFSIZ]; + + fputs("\n# =============", stream); + fputs("\n# Recur. Events", stream); + fputs("\n# =============\n", stream); + fputs("# (pcal does not support from..until dates specification\n", stream); + + LLIST_FOREACH(&recur_elist, i) { + struct recur_event *rev = LLIST_GET_DATA(i); + if (rev->rpt->until == 0 && rev->rpt->freq == 1) { + switch (rev->rpt->type) { + case RECUR_DAILY: + date_sec2date_fmt(rev->day, "%b %d", pcal_date); + fprintf(stream, "all day on_or_after %s %s\n", pcal_date, rev->mesg); + break; + case RECUR_WEEKLY: + date_sec2date_fmt(rev->day, "%a", pcal_date); + fprintf(stream, "all %s on_or_after ", pcal_date); + date_sec2date_fmt(rev->day, "%b %d", pcal_date); + fprintf(stream, "%s %s\n", pcal_date, rev->mesg); + break; + case RECUR_MONTHLY: + date_sec2date_fmt(rev->day, "%d", pcal_date); + fprintf(stream, "day on all %s %s\n", pcal_date, rev->mesg); + break; + case RECUR_YEARLY: + date_sec2date_fmt(rev->day, "%b %d", pcal_date); + fprintf(stream, "%s %s\n", pcal_date, rev->mesg); + break; + default: + EXIT(_("incoherent repetition type")); + } + } else { + const long YEAR_START = calendar_start_of_year(); + const long YEAR_END = calendar_end_of_year(); + + if (rev->day < YEAR_END && rev->day > YEAR_START) + foreach_date_dump(YEAR_END, rev->rpt, &rev->exc, rev->day, 0, + rev->mesg, (cb_dump_t) pcal_dump_event, stream); + } + } +} + +static void pcal_export_events(FILE * stream) +{ + llist_item_t *i; + + fputs("\n# ======\n# Events\n# ======\n", stream); + LLIST_FOREACH(&eventlist, i) { + struct event *ev = LLIST_TS_GET_DATA(i); + pcal_dump_event(stream, ev->day, 0, ev->mesg); + } + fputc('\n', stream); +} + +static void pcal_export_recur_apoints(FILE * stream) +{ + llist_item_t *i; + char pcal_date[BUFSIZ], pcal_beg[BUFSIZ], pcal_end[BUFSIZ]; + + fputs("\n# ==============", stream); + fputs("\n# Recur. Apoints", stream); + fputs("\n# ==============\n", stream); + fputs("# (pcal does not support from..until dates specification\n", stream); + + LLIST_TS_FOREACH(&recur_alist_p, i) { + struct recur_apoint *rapt = LLIST_TS_GET_DATA(i); + + if (rapt->rpt->until == 0 && rapt->rpt->freq == 1) { + date_sec2date_fmt(rapt->start, "%R", pcal_beg); + date_sec2date_fmt(rapt->start + rapt->dur, "%R", pcal_end); + switch (rapt->rpt->type) { + case RECUR_DAILY: + date_sec2date_fmt(rapt->start, "%b %d", pcal_date); + fprintf(stream, "all day on_or_after %s (%s -> %s) %s\n", + pcal_date, pcal_beg, pcal_end, rapt->mesg); + break; + case RECUR_WEEKLY: + date_sec2date_fmt(rapt->start, "%a", pcal_date); + fprintf(stream, "all %s on_or_after ", pcal_date); + date_sec2date_fmt(rapt->start, "%b %d", pcal_date); + fprintf(stream, "%s (%s -> %s) %s\n", pcal_date, pcal_beg, + pcal_end, rapt->mesg); + break; + case RECUR_MONTHLY: + date_sec2date_fmt(rapt->start, "%d", pcal_date); + fprintf(stream, "day on all %s (%s -> %s) %s\n", pcal_date, + pcal_beg, pcal_end, rapt->mesg); + break; + case RECUR_YEARLY: + date_sec2date_fmt(rapt->start, "%b %d", pcal_date); + fprintf(stream, "%s (%s -> %s) %s\n", pcal_date, pcal_beg, + pcal_end, rapt->mesg); + break; + default: + EXIT(_("incoherent repetition type")); + } + } else { + const long YEAR_START = calendar_start_of_year(); + const long YEAR_END = calendar_end_of_year(); + + if (rapt->start < YEAR_END && rapt->start > YEAR_START) + foreach_date_dump(YEAR_END, rapt->rpt, &rapt->exc, rapt->start, + rapt->dur, rapt->mesg, + (cb_dump_t) pcal_dump_apoint, stream); + } + } +} + +static void pcal_export_apoints(FILE * stream) +{ + llist_item_t *i; + + fputs("\n# ============\n# Appointments\n# ============\n", stream); + LLIST_TS_LOCK(&alist_p); + LLIST_TS_FOREACH(&alist_p, i) { + struct apoint *apt = LLIST_TS_GET_DATA(i); + pcal_dump_apoint(stream, apt->start, apt->dur, apt->mesg); + } + LLIST_TS_UNLOCK(&alist_p); + fputc('\n', stream); +} + +static void pcal_export_todo(FILE * stream) +{ + llist_item_t *i; + + fputs("#\n# Todos\n#\n", stream); + LLIST_FOREACH(&todolist, i) { + struct todo *todo = LLIST_TS_GET_DATA(i); + if (todo->id < 0) /* completed items */ + continue; + + fputs("note all ", stream); + fprintf(stream, "%d. %s\n", todo->id, todo->mesg); + } + fputc('\n', stream); +} + +/* Export calcurse data. */ +void pcal_export_data(FILE * stream) +{ + pcal_export_header(stream); + pcal_export_recur_events(stream); + pcal_export_events(stream); + pcal_export_recur_apoints(stream); + pcal_export_apoints(stream); + pcal_export_todo(stream); + pcal_export_footer(stream); +} diff --git a/src/recur.c b/src/recur.c index caa5ec3..dad9c25 100644 --- a/src/recur.c +++ b/src/recur.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -42,242 +42,217 @@ #include "calcurse.h" -llist_ts_t recur_alist_p; -llist_t recur_elist; -static struct recur_event bkp_cut_recur_event; +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) +static void free_exc(struct excp *exc) { - mem_free (exc); + mem_free(exc); } -static void -free_exc_list (llist_t *exc) +static void free_exc_list(llist_t * exc) { - LLIST_FREE_INNER (exc, free_exc); - LLIST_FREE (exc); + LLIST_FREE_INNER(exc, free_exc); + LLIST_FREE(exc); } -static int -exc_cmp_day (struct excp *a, struct excp *b) +static int exc_cmp_day(struct excp *a, struct excp *b) { - return (a->st < b->st ? -1 : (a->st == b->st ? 0 : 1)); + return a->st < b->st ? -1 : (a->st == b->st ? 0 : 1); } -static void -recur_add_exc (llist_t *exc, long day) +static void recur_add_exc(llist_t * exc, long day) { - struct excp *o = mem_malloc (sizeof (struct excp)); + struct excp *o = mem_malloc(sizeof(struct excp)); o->st = day; - LLIST_ADD_SORTED (exc, o, exc_cmp_day); + LLIST_ADD_SORTED(exc, o, exc_cmp_day); } -static void -exc_dup (llist_t *in, llist_t *exc) +static void exc_dup(llist_t * in, llist_t * exc) { llist_item_t *i; - LLIST_INIT (in); + LLIST_INIT(in); - if (exc) - { - LLIST_FOREACH (exc, i) - { - struct excp *p = LLIST_GET_DATA (i); - recur_add_exc (in, p->st); - } + if (exc) { + LLIST_FOREACH(exc, i) { + struct excp *p = LLIST_GET_DATA(i); + recur_add_exc(in, p->st); } + } } -void -recur_event_free_bkp (enum eraseflg flag) +void recur_event_free_bkp(void) { - 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, flag); + 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 (enum eraseflg flag) +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, flag); + 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); } -static void -recur_event_dup (struct recur_event *in, struct recur_event *bkp) +static void recur_event_dup(struct recur_event *in, struct recur_event *bkp) { - EXIT_IF (!in || !bkp, _("null pointer")); + EXIT_IF(!in || !bkp, _("null pointer")); bkp->id = in->id; bkp->day = in->day; - bkp->mesg = mem_strdup (in->mesg); + bkp->mesg = mem_strdup(in->mesg); - bkp->rpt = mem_malloc (sizeof (struct rpt)); + 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; - exc_dup (&bkp->exc, &in->exc); + exc_dup(&bkp->exc, &in->exc); if (in->note) - bkp->note = mem_strdup (in->note); + bkp->note = mem_strdup(in->note); } -static void -recur_apoint_dup (struct recur_apoint *in, struct recur_apoint *bkp) +static void recur_apoint_dup(struct recur_apoint *in, struct recur_apoint *bkp) { - EXIT_IF (!in || !bkp, _("null pointer")); + EXIT_IF(!in || !bkp, _("null pointer")); bkp->start = in->start; bkp->dur = in->dur; bkp->state = in->state; - bkp->mesg = mem_strdup (in->mesg); + bkp->mesg = mem_strdup(in->mesg); - bkp->rpt = mem_malloc (sizeof (struct rpt)); + 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; - exc_dup (&bkp->exc, &in->exc); + exc_dup(&bkp->exc, &in->exc); if (in->note) - bkp->note = mem_strdup (in->note); + bkp->note = mem_strdup(in->note); } -void -recur_apoint_llist_init (void) +void recur_apoint_llist_init(void) { - LLIST_TS_INIT (&recur_alist_p); + LLIST_TS_INIT(&recur_alist_p); } -static void -recur_apoint_free (struct recur_apoint *rapt) +static void recur_apoint_free(struct recur_apoint *rapt) { - mem_free (rapt->mesg); + mem_free(rapt->mesg); if (rapt->note) - mem_free (rapt->note); + mem_free(rapt->note); if (rapt->rpt) - mem_free (rapt->rpt); - free_exc_list (&rapt->exc); - mem_free (rapt); + mem_free(rapt->rpt); + free_exc_list(&rapt->exc); + mem_free(rapt); } -static void -recur_event_free (struct recur_event *rev) +static void recur_event_free(struct recur_event *rev) { - mem_free (rev->mesg); + mem_free(rev->mesg); if (rev->note) - mem_free (rev->note); + mem_free(rev->note); if (rev->rpt) - mem_free (rev->rpt); - free_exc_list (&rev->exc); - mem_free (rev); + mem_free(rev->rpt); + free_exc_list(&rev->exc); + mem_free(rev); } -void -recur_apoint_llist_free (void) +void recur_apoint_llist_free(void) { - LLIST_TS_FREE_INNER (&recur_alist_p, recur_apoint_free); - LLIST_TS_FREE (&recur_alist_p); + LLIST_TS_FREE_INNER(&recur_alist_p, recur_apoint_free); + LLIST_TS_FREE(&recur_alist_p); } -void -recur_event_llist_free (void) +void recur_event_llist_free(void) { - LLIST_FREE_INNER (&recur_elist, recur_event_free); - LLIST_FREE (&recur_elist); + LLIST_FREE_INNER(&recur_elist, recur_event_free); + LLIST_FREE(&recur_elist); } static int -recur_apoint_cmp_start (struct recur_apoint *a, struct recur_apoint *b) +recur_apoint_cmp_start(struct recur_apoint *a, struct recur_apoint *b) { - return (a->start < b->start ? -1 : (a->start == b->start ? 0 : 1)); + return a->start < b->start ? -1 : (a->start == b->start ? 0 : 1); } -static int -recur_event_cmp_day (struct recur_event *a, struct recur_event *b) +static int recur_event_cmp_day(struct recur_event *a, struct recur_event *b) { - return (a->day < b->day ? -1 : (a->day == b->day ? 0 : 1)); + return a->day < b->day ? -1 : (a->day == b->day ? 0 : 1); } /* Insert a new recursive appointment in the general linked list */ -struct recur_apoint * -recur_apoint_new (char *mesg, char *note, long start, long dur, char state, - int type, int freq, long until, llist_t *except) +struct recur_apoint *recur_apoint_new(char *mesg, char *note, long start, + long dur, char state, int type, int freq, + long until, llist_t * except) { - struct recur_apoint *rapt = mem_malloc (sizeof (struct recur_apoint)); + struct recur_apoint *rapt = mem_malloc(sizeof(struct recur_apoint)); - rapt->rpt = mem_malloc (sizeof (struct rpt)); - rapt->mesg = mem_strdup (mesg); - rapt->note = (note != NULL) ? mem_strdup (note) : 0; + rapt->rpt = mem_malloc(sizeof(struct rpt)); + rapt->mesg = mem_strdup(mesg); + rapt->note = (note != NULL) ? mem_strdup(note) : 0; rapt->start = start; rapt->state = state; rapt->dur = dur; rapt->rpt->type = type; rapt->rpt->freq = freq; rapt->rpt->until = until; - if (except) - { - exc_dup (&rapt->exc, except); - free_exc_list (except); - } - else - LLIST_INIT (&rapt->exc); + if (except) { + exc_dup(&rapt->exc, except); + free_exc_list(except); + } else + LLIST_INIT(&rapt->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); + LLIST_TS_LOCK(&recur_alist_p); + LLIST_TS_ADD_SORTED(&recur_alist_p, rapt, recur_apoint_cmp_start); + LLIST_TS_UNLOCK(&recur_alist_p); return rapt; } /* Insert a new recursive event in the general linked list */ -struct recur_event * -recur_event_new (char *mesg, char *note, long day, int id, int type, int freq, - long until, llist_t *except) +struct recur_event *recur_event_new(char *mesg, char *note, long day, int id, + int type, int freq, long until, + llist_t * except) { - struct recur_event *rev = mem_malloc (sizeof (struct recur_event)); + struct recur_event *rev = mem_malloc(sizeof(struct recur_event)); - rev->rpt = mem_malloc (sizeof (struct rpt)); - rev->mesg = mem_strdup (mesg); - rev->note = (note != NULL) ? mem_strdup (note) : 0; + rev->rpt = mem_malloc(sizeof(struct rpt)); + rev->mesg = mem_strdup(mesg); + rev->note = (note != NULL) ? mem_strdup(note) : 0; rev->day = day; rev->id = id; rev->rpt->type = type; rev->rpt->freq = freq; rev->rpt->until = until; - if (except) - { - exc_dup (&rev->exc, except); - free_exc_list (except); - } - else - LLIST_INIT (&rev->exc); + if (except) { + exc_dup(&rev->exc, except); + free_exc_list(except); + } else + LLIST_INIT(&rev->exc); - LLIST_ADD_SORTED (&recur_elist, rev, recur_event_cmp_day); + LLIST_ADD_SORTED(&recur_elist, rev, recur_event_cmp_day); return rev; } @@ -286,214 +261,195 @@ recur_event_new (char *mesg, char *note, long day, int id, int type, int freq, * Correspondance between the defines on recursive type, * and the letter to be written in file. */ -char -recur_def2char (enum recur_type define) +char recur_def2char(enum recur_type define) { char recur_char; - switch (define) - { - case RECUR_DAILY: - recur_char = 'D'; - break; - case RECUR_WEEKLY: - recur_char = 'W'; - break; - case RECUR_MONTHLY: - recur_char = 'M'; - break; - case RECUR_YEARLY: - recur_char = 'Y'; - break; - default: - EXIT (_("unknown repetition type")); - return 0; - } + switch (define) { + case RECUR_DAILY: + recur_char = 'D'; + break; + case RECUR_WEEKLY: + recur_char = 'W'; + break; + case RECUR_MONTHLY: + recur_char = 'M'; + break; + case RECUR_YEARLY: + recur_char = 'Y'; + break; + default: + EXIT(_("unknown repetition type")); + return 0; + } - return (recur_char); + return recur_char; } /* * Correspondance between the letters written in file and the defines * concerning the recursive type. */ -int -recur_char2def (char type) +int recur_char2def(char type) { int recur_def; - switch (type) - { - case 'D': - recur_def = RECUR_DAILY; - break; - case 'W': - recur_def = RECUR_WEEKLY; - break; - case 'M': - recur_def = RECUR_MONTHLY; - break; - case 'Y': - recur_def = RECUR_YEARLY; - break; - default: - EXIT (_("unknown character")); - return 0; - } - return (recur_def); + switch (type) { + case 'D': + recur_def = RECUR_DAILY; + break; + case 'W': + recur_def = RECUR_WEEKLY; + break; + case 'M': + recur_def = RECUR_MONTHLY; + break; + case 'Y': + recur_def = RECUR_YEARLY; + break; + default: + EXIT(_("unknown character")); + return 0; + } + return recur_def; } /* Write days for which recurrent items should not be repeated. */ -static void -recur_write_exc (llist_t *lexc, FILE *f) +static void recur_write_exc(llist_t * lexc, FILE * f) { llist_item_t *i; struct tm *lt; time_t t; int st_mon, st_day, st_year; - LLIST_FOREACH (lexc, i) - { - struct excp *exc = LLIST_GET_DATA (i); - t = exc->st; - lt = localtime (&t); - st_mon = lt->tm_mon + 1; - st_day = lt->tm_mday; - st_year = lt->tm_year + 1900; - (void)fprintf (f, " !%02u/%02u/%04u", st_mon, st_day, st_year); - } + LLIST_FOREACH(lexc, i) { + struct excp *exc = LLIST_GET_DATA(i); + t = exc->st; + lt = localtime(&t); + st_mon = lt->tm_mon + 1; + st_day = lt->tm_mday; + st_year = lt->tm_year + 1900; + fprintf(f, " !%02u/%02u/%04u", st_mon, st_day, st_year); + } } /* Load the recursive appointment description */ -struct recur_apoint * -recur_apoint_scan (FILE *f, struct tm start, struct tm end, char type, - int freq, struct tm until, char *note, llist_t *exc, - char state) +struct recur_apoint *recur_apoint_scan(FILE * f, struct tm start, struct tm end, + char type, int freq, struct tm until, + char *note, llist_t * exc, char state) { char buf[BUFSIZ], *nl; time_t tstart, tend, tuntil; /* Read the appointment description */ - (void)fgets (buf, sizeof buf, f); - nl = strchr (buf, '\n'); - if (nl) - { - *nl = '\0'; - } + if (!fgets(buf, sizeof buf, f)) + return NULL; + + nl = strchr(buf, '\n'); + if (nl) { + *nl = '\0'; + } start.tm_sec = end.tm_sec = 0; start.tm_isdst = end.tm_isdst = -1; start.tm_year -= 1900; start.tm_mon--; end.tm_year -= 1900; end.tm_mon--; - tstart = mktime (&start); - tend = mktime (&end); - - if (until.tm_year != 0) - { - until.tm_hour = 23; - until.tm_min = 59; - until.tm_sec = 0; - until.tm_isdst = -1; - until.tm_year -= 1900; - until.tm_mon--; - tuntil = mktime (&until); - } - else - { - tuntil = 0; - } - EXIT_IF (tstart == -1 || tend == -1 || tstart > tend || tuntil == -1, - _("date error in appointment")); - - return (recur_apoint_new (buf, note, tstart, tend - tstart, state, - recur_char2def (type), freq, tuntil, exc)); + tstart = mktime(&start); + tend = mktime(&end); + + if (until.tm_year != 0) { + until.tm_hour = 23; + until.tm_min = 59; + until.tm_sec = 0; + until.tm_isdst = -1; + until.tm_year -= 1900; + until.tm_mon--; + tuntil = mktime(&until); + } else { + tuntil = 0; + } + EXIT_IF(tstart == -1 || tend == -1 || tstart > tend || tuntil == -1, + _("date error in appointment")); + + return recur_apoint_new(buf, note, tstart, tend - tstart, state, + recur_char2def(type), freq, tuntil, exc); } /* Load the recursive events from file */ -struct recur_event * -recur_event_scan (FILE *f, struct tm start, int id, char type, int freq, - struct tm until, char *note, llist_t *exc) +struct recur_event *recur_event_scan(FILE * f, struct tm start, int id, + char type, int freq, struct tm until, + char *note, llist_t * exc) { char buf[BUFSIZ], *nl; time_t tstart, tuntil; /* Read the event description */ - (void)fgets (buf, sizeof buf, f); - nl = strchr (buf, '\n'); - if (nl) - { - *nl = '\0'; - } - start.tm_hour = until.tm_hour = 12; + if (!fgets(buf, sizeof buf, f)) + return NULL; + + nl = strchr(buf, '\n'); + if (nl) { + *nl = '\0'; + } + start.tm_hour = until.tm_hour = 0; start.tm_min = until.tm_min = 0; start.tm_sec = until.tm_sec = 0; start.tm_isdst = until.tm_isdst = -1; start.tm_year -= 1900; start.tm_mon--; - if (until.tm_year != 0) - { - until.tm_year -= 1900; - until.tm_mon--; - tuntil = mktime (&until); - } - else - { - tuntil = 0; - } - tstart = mktime (&start); - EXIT_IF (tstart == -1 || tuntil == -1, - _("date error in event")); - - return recur_event_new (buf, note, tstart, id, recur_char2def (type), - freq, tuntil, exc); + if (until.tm_year != 0) { + until.tm_year -= 1900; + until.tm_mon--; + tuntil = mktime(&until); + } else { + tuntil = 0; + } + tstart = mktime(&start); + EXIT_IF(tstart == -1 || tuntil == -1, _("date error in event")); + + return recur_event_new(buf, note, tstart, id, recur_char2def(type), freq, + tuntil, exc); } /* Writting of a recursive appointment into file. */ -static void -recur_apoint_write (struct recur_apoint *o, FILE *f) +void recur_apoint_write(struct recur_apoint *o, FILE * f) { struct tm *lt; time_t t; t = o->start; - lt = localtime (&t); - (void)fprintf (f, "%02u/%02u/%04u @ %02u:%02u", - lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, - lt->tm_hour, lt->tm_min); + lt = localtime(&t); + fprintf(f, "%02u/%02u/%04u @ %02u:%02u", lt->tm_mon + 1, lt->tm_mday, + 1900 + lt->tm_year, lt->tm_hour, lt->tm_min); t = o->start + o->dur; - lt = localtime (&t); - (void)fprintf (f, " -> %02u/%02u/%04u @ %02u:%02u", - lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, - lt->tm_hour, lt->tm_min); + lt = localtime(&t); + fprintf(f, " -> %02u/%02u/%04u @ %02u:%02u", lt->tm_mon + 1, lt->tm_mday, + 1900 + lt->tm_year, lt->tm_hour, lt->tm_min); t = o->rpt->until; - if (t == 0) - { /* We have an endless recurrent appointment. */ - (void)fprintf (f, " {%d%c", o->rpt->freq, recur_def2char (o->rpt->type)); - } - else - { - lt = localtime (&t); - (void)fprintf (f, " {%d%c -> %02u/%02u/%04u", - o->rpt->freq, recur_def2char (o->rpt->type), - lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year); - } - recur_write_exc (&o->exc, f); - (void)fprintf (f, "} "); + if (t == 0) { /* We have an endless recurrent appointment. */ + fprintf(f, " {%d%c", o->rpt->freq, recur_def2char(o->rpt->type)); + } else { + lt = localtime(&t); + fprintf(f, " {%d%c -> %02u/%02u/%04u", o->rpt->freq, + recur_def2char(o->rpt->type), lt->tm_mon + 1, lt->tm_mday, + 1900 + lt->tm_year); + } + recur_write_exc(&o->exc, f); + fputs("} ", f); if (o->note != NULL) - (void)fprintf (f, ">%s ", o->note); + fprintf(f, ">%s ", o->note); if (o->state & APOINT_NOTIFY) - (void)fprintf (f, "!"); + fputc('!', f); else - (void)fprintf (f, "|"); - (void)fprintf (f, "%s\n", o->mesg); + fputc('|', f); + fprintf(f, "%s\n", o->mesg); } /* Writting of a recursive event into file. */ -static void -recur_event_write (struct recur_event *o, FILE *f) +void recur_event_write(struct recur_event *o, FILE * f) { struct tm *lt; time_t t; @@ -501,61 +457,52 @@ recur_event_write (struct recur_event *o, FILE *f) int end_mon, end_day, end_year; t = o->day; - lt = localtime (&t); + lt = localtime(&t); st_mon = lt->tm_mon + 1; st_day = lt->tm_mday; st_year = lt->tm_year + 1900; t = o->rpt->until; - if (t == 0) - { /* We have an endless recurrent event. */ - (void)fprintf (f, "%02u/%02u/%04u [%d] {%d%c", - st_mon, st_day, st_year, o->id, o->rpt->freq, - recur_def2char (o->rpt->type)); - } - else - { - lt = localtime (&t); - end_mon = lt->tm_mon + 1; - end_day = lt->tm_mday; - end_year = lt->tm_year + 1900; - (void)fprintf (f, "%02u/%02u/%04u [%d] {%d%c -> %02u/%02u/%04u", - st_mon, st_day, st_year, o->id, - o->rpt->freq, recur_def2char (o->rpt->type), - end_mon, end_day, end_year); - } - recur_write_exc (&o->exc, f); - (void)fprintf (f, "} "); + if (t == 0) { /* We have an endless recurrent event. */ + fprintf(f, "%02u/%02u/%04u [%d] {%d%c", st_mon, st_day, st_year, o->id, + o->rpt->freq, recur_def2char(o->rpt->type)); + } else { + lt = localtime(&t); + end_mon = lt->tm_mon + 1; + end_day = lt->tm_mday; + end_year = lt->tm_year + 1900; + fprintf(f, "%02u/%02u/%04u [%d] {%d%c -> %02u/%02u/%04u", st_mon, + st_day, st_year, o->id, o->rpt->freq, + recur_def2char(o->rpt->type), end_mon, end_day, end_year); + } + recur_write_exc(&o->exc, f); + fputs("} ", f); if (o->note != NULL) - (void)fprintf (f, ">%s ", o->note); - (void)fprintf (f, "%s\n", o->mesg); + fprintf(f, ">%s ", o->note); + fprintf(f, "%s\n", o->mesg); } /* Write recursive items to file. */ -void -recur_save_data (FILE *f) +void recur_save_data(FILE * f) { llist_item_t *i; - LLIST_FOREACH (&recur_elist, i) - { - struct recur_event *rev = LLIST_GET_DATA (i); - recur_event_write (rev, f); - } - - LLIST_TS_LOCK (&recur_alist_p); - LLIST_TS_FOREACH (&recur_alist_p, i) - { - struct recur_apoint *rapt = LLIST_GET_DATA (i); - recur_apoint_write (rapt, f); - } - LLIST_TS_UNLOCK (&recur_alist_p); + LLIST_FOREACH(&recur_elist, i) { + struct recur_event *rev = LLIST_GET_DATA(i); + recur_event_write(rev, f); + } + + LLIST_TS_LOCK(&recur_alist_p); + LLIST_TS_FOREACH(&recur_alist_p, i) { + struct recur_apoint *rapt = LLIST_GET_DATA(i); + recur_apoint_write(rapt, f); + } + LLIST_TS_UNLOCK(&recur_alist_p); } - /* - * The two following defines together with the diff_days, diff_weeks, - * diff_months and diff_years functions were provided by Lukas Fleischer to - * correct the wrong calculation of recurrent dates after a turn of year. + * The two following defines together with the diff_days, diff_months and + * diff_years functions were provided by Lukas Fleischer to correct the wrong + * calculation of recurrent dates after a turn of year. */ #define BC(start, end, bs) \ (((end) - (start) + ((start) % bs) - ((end) % bs)) / bs \ @@ -564,10 +511,8 @@ recur_save_data (FILE *f) #define LEAPCOUNT(start, end) \ (BC(start, end, 4) - BC(start, end, 100) + BC(start, end, 400)) - /* Calculate the difference in days between two dates. */ -static long -diff_days (struct tm lt_start, struct tm lt_end) +static long diff_days(struct tm lt_start, struct tm lt_end) { long diff; @@ -576,26 +521,17 @@ diff_days (struct tm lt_start, struct tm lt_end) diff = lt_end.tm_yday - lt_start.tm_yday; - if (lt_end.tm_year > lt_start.tm_year) - { - diff += (lt_end.tm_year - lt_start.tm_year) * YEARINDAYS; - diff += LEAPCOUNT (lt_start.tm_year + TM_YEAR_BASE, - lt_end.tm_year + TM_YEAR_BASE - 1); - } + if (lt_end.tm_year > lt_start.tm_year) { + diff += (lt_end.tm_year - lt_start.tm_year) * YEARINDAYS; + diff += LEAPCOUNT(lt_start.tm_year + TM_YEAR_BASE, + lt_end.tm_year + TM_YEAR_BASE - 1); + } return diff; } -/* Calculate the difference in weeks between two dates. */ -static long -diff_weeks (struct tm lt_start, struct tm lt_end) -{ - return diff_days (lt_start, lt_end) / WEEKINDAYS; -} - /* Calculate the difference in months between two dates. */ -static long -diff_months (struct tm lt_start, struct tm lt_end) +static long diff_months(struct tm lt_start, struct tm lt_end) { long diff; @@ -609,21 +545,19 @@ diff_months (struct tm lt_start, struct tm lt_end) } /* Calculate the difference in years between two dates. */ -static long -diff_years (struct tm lt_start, struct tm lt_end) +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); } /* - * Check if the recurrent item belongs to the selected day, - * and if yes, return the real start time. + * Check if the recurrent item belongs to the selected day, and if yes, store + * the start date of the occurrence that belongs to the day in a buffer. * * This function was improved thanks to Tony's patch. * Thanks also to youshe for reporting daylight saving time related problems. @@ -631,92 +565,129 @@ exc_inday (struct excp *exc, long day_start) * calculation of recurrent dates after a turn of years. */ unsigned -recur_item_inday (long item_start, llist_t *item_exc, int rpt_type, - int rpt_freq, long rpt_until, long day_start) +recur_item_find_occurrence(long item_start, long item_dur, llist_t * item_exc, + int rpt_type, int rpt_freq, long rpt_until, + long day_start, unsigned *occurrence) { struct date start_date; - long day_end, diff; - struct tm lt_item, lt_day; + long diff, span; + struct tm lt_day, lt_item, lt_item_day; time_t t; - day_end = day_start + DAYINSEC; + if (day_start < item_start - DAYINSEC + 1) + return 0; + + if (rpt_until != 0 && day_start >= rpt_until + item_dur) + return 0; + t = day_start; - lt_day = *localtime (&t); + lt_day = *localtime(&t); - if (LLIST_FIND_FIRST (item_exc, day_start, exc_inday)) + t = item_start; + lt_item = *localtime(&t); + + lt_item_day = lt_item; + lt_item_day.tm_sec = lt_item_day.tm_min = lt_item_day.tm_hour = 0; + + span = (item_start - mktime(<_item_day) + item_dur - 1) / DAYINSEC; + + switch (rpt_type) { + case RECUR_DAILY: + diff = diff_days(lt_item_day, lt_day) % rpt_freq; + lt_item_day.tm_mday = lt_day.tm_mday - diff; + lt_item_day.tm_mon = lt_day.tm_mon; + lt_item_day.tm_year = lt_day.tm_year; + break; + case RECUR_WEEKLY: + diff = diff_days(lt_item_day, lt_day) % (rpt_freq * WEEKINDAYS); + lt_item_day.tm_mday = lt_day.tm_mday - diff; + lt_item_day.tm_mon = lt_day.tm_mon; + lt_item_day.tm_year = lt_day.tm_year; + break; + case RECUR_MONTHLY: + diff = diff_months(lt_item_day, lt_day) % rpt_freq; + if (lt_day.tm_mday < lt_item_day.tm_mday) + diff++; + lt_item_day.tm_mon = lt_day.tm_mon - diff; + lt_item_day.tm_year = lt_day.tm_year; + break; + case RECUR_YEARLY: + diff = diff_years(lt_item_day, lt_day) % rpt_freq; + if (lt_day.tm_mon < lt_item_day.tm_mon || + (lt_day.tm_mon == lt_item_day.tm_mon && + lt_day.tm_mday < lt_item_day.tm_mday)) + diff++; + lt_item_day.tm_year = lt_day.tm_year - diff; + break; + default: + EXIT(_("unknown item type")); + } + + lt_item_day.tm_isdst = lt_day.tm_isdst; + t = mktime(<_item_day); + + if (LLIST_FIND_FIRST(item_exc, t, exc_inday)) return 0; - if (rpt_until == 0) /* we have an endless recurrent item */ - rpt_until = day_end; + if (rpt_until != 0 && t > rpt_until) + return 0; - if (item_start > day_end || rpt_until < day_start) - return (0); + lt_item_day = *localtime(&t); + diff = diff_days(lt_item_day, lt_day); - t = item_start; - lt_item = *localtime (&t); - - switch (rpt_type) - { - case RECUR_DAILY: - diff = diff_days (lt_item, lt_day); - if (diff % rpt_freq != 0) - return (0); - lt_item.tm_mday = lt_day.tm_mday; - lt_item.tm_mon = lt_day.tm_mon; - lt_item.tm_year = lt_day.tm_year; - break; - case RECUR_WEEKLY: - if (lt_item.tm_wday != lt_day.tm_wday) - return (0); - else - { - diff = diff_weeks (lt_item, lt_day); - if (diff % rpt_freq != 0) - return (0); - } - lt_item.tm_mday = lt_day.tm_mday; - lt_item.tm_mon = lt_day.tm_mon; - lt_item.tm_year = lt_day.tm_year; - break; - case RECUR_MONTHLY: - diff = diff_months (lt_item, lt_day); - if (diff % rpt_freq != 0) - return (0); - lt_item.tm_mon = lt_day.tm_mon; - lt_item.tm_year = lt_day.tm_year; - break; - case RECUR_YEARLY: - diff = diff_years (lt_item, lt_day); - if (diff % rpt_freq != 0) - return (0); - lt_item.tm_year = lt_day.tm_year; - break; - default: - EXIT (_("unknown item type")); + if (diff <= span) { + if (occurrence) { + start_date.dd = lt_item_day.tm_mday; + start_date.mm = lt_item_day.tm_mon + 1; + start_date.yyyy = lt_item_day.tm_year + 1900; + + *occurrence = date2sec(start_date, lt_item.tm_hour, lt_item.tm_min); } - start_date.dd = lt_item.tm_mday; - start_date.mm = lt_item.tm_mon + 1; - start_date.yyyy = lt_item.tm_year + 1900; - item_start = date2sec (start_date, lt_item.tm_hour, lt_item.tm_min); - if (item_start < day_end && item_start >= day_start) - return (item_start); - else - return (0); + return 1; + } else + return 0; +} + +unsigned +recur_apoint_find_occurrence(struct recur_apoint *rapt, long day_start, + unsigned *occurrence) +{ + return recur_item_find_occurrence(rapt->start, rapt->dur, &rapt->exc, + rapt->rpt->type, rapt->rpt->freq, + rapt->rpt->until, day_start, occurrence); } unsigned -recur_apoint_inday(struct recur_apoint *rapt, long day_start) +recur_event_find_occurrence(struct recur_event *rev, long day_start, + unsigned *occurrence) { - return recur_item_inday (rapt->start, &rapt->exc, rapt->rpt->type, - rapt->rpt->freq, rapt->rpt->until, day_start); + return recur_item_find_occurrence(rev->day, DAYINSEC, &rev->exc, + rev->rpt->type, rev->rpt->freq, + rev->rpt->until, day_start, occurrence); } +/* Check if a recurrent item belongs to the selected day. */ unsigned -recur_event_inday(struct recur_event *rev, long day_start) +recur_item_inday(long item_start, long item_dur, llist_t * item_exc, + int rpt_type, int rpt_freq, long rpt_until, long day_start) +{ + /* We do not need the (real) start time of the occurrence here, so just + * ignore the buffer. */ + return recur_item_find_occurrence(item_start, item_dur, item_exc, rpt_type, + rpt_freq, rpt_until, day_start, NULL); +} + +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); +} + +unsigned recur_event_inday(struct recur_event *rev, long day_start) { - return recur_item_inday (rev->day, &rev->exc, rev->rpt->type, rev->rpt->freq, - rev->rpt->until, day_start); + return recur_item_inday(rev->day, DAYINSEC, &rev->exc, rev->rpt->type, + rev->rpt->freq, rev->rpt->until, day_start); } /* @@ -724,46 +695,40 @@ 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(long start, unsigned num, unsigned delete_whole, + enum eraseflg flag) { llist_item_t *i; - i = LLIST_FIND_NTH (&recur_elist, num, start, recur_event_inday); + i = LLIST_FIND_NTH(&recur_elist, num, start, recur_event_inday); 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, flag); - break; - case ERASE_CUT: - recur_event_free_bkp (ERASE_FORCE); - recur_event_dup (rev, &bkp_cut_recur_event); - erase_note (&rev->note, ERASE_FORCE_KEEP_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); - if (flag != ERASE_FORCE_KEEP_NOTE && flag != ERASE_CUT) - erase_note (&rev->note, flag); - mem_free (rev); - break; - } + 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); + } else + recur_add_exc(&rev->exc, start); } /* @@ -771,57 +736,50 @@ 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(long start, unsigned num, unsigned delete_whole, + enum eraseflg flag) { llist_item_t *i; int need_check_notify = 0; - i = LLIST_TS_FIND_NTH (&recur_alist_p, num, start, recur_apoint_inday); + i = LLIST_TS_FIND_NTH(&recur_alist_p, num, start, recur_apoint_inday); 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) - need_check_notify = notify_same_recur_item (rapt); - if (delete_whole) - { - switch (flag) - { - case ERASE_FORCE_ONLY_NOTE: - erase_note (&rapt->note, flag); - break; - case ERASE_CUT: - recur_apoint_free_bkp (ERASE_FORCE); - recur_apoint_dup (rapt, &bkp_cut_recur_apoint); - erase_note (&rapt->note, ERASE_FORCE_KEEP_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); - if (flag != ERASE_FORCE_KEEP_NOTE && flag != ERASE_CUT) - erase_note (&rapt->note, flag); - mem_free (rapt); - if (need_check_notify) - notify_check_next_app (0); - break; - } - } - else - { - recur_add_exc (&rapt->exc, start); + 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) + 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); + notify_check_next_app(0); + break; } - LLIST_TS_UNLOCK (&recur_alist_p); + } else { + recur_add_exc(&rapt->exc, start); + if (need_check_notify) + notify_check_next_app(0); + } + LLIST_TS_UNLOCK(&recur_alist_p); } /* @@ -831,319 +789,289 @@ recur_apoint_erase (long start, unsigned num, unsigned delete_whole, * o repetition end date * and then delete the selected item to recreate it as a recurrent one */ -void -recur_repeat_item (struct conf *conf) +void recur_repeat_item(void) { struct tm *lt; time_t t; - int ch = 0; int date_entered = 0; int year = 0, month = 0, day = 0; struct date until_date; char outstr[BUFSIZ]; char user_input[BUFSIZ] = ""; - char *mesg_type_1 = - _("Enter the repetition type: (D)aily, (W)eekly, (M)onthly, (Y)early"); - char *mesg_type_2 = _("[D/W/M/Y] "); - char *mesg_freq_1 = _("Enter the repetition frequence:"); - char *mesg_wrong_freq = _("The frequence you entered is not valid."); - char *mesg_until_1 = - _("Enter the ending date: [%s] or '0' for an endless repetition"); - char *mesg_wrong_1 = _("The entered date is not valid."); - char *mesg_wrong_2 = - _("Possible formats are [%s] or '0' for an endless repetition"); - char *wrong_type_1 = _("This item is already a repeated one."); - char *wrong_type_2 = _("Press [ENTER] to continue."); - char *mesg_older = - _("Sorry, the date you entered is older than the item start time."); + 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); - (void)wgetch (win[STA].p); - return; - } - - while ((ch != 'D') && (ch != 'W') && (ch != 'M') - && (ch != 'Y') && (ch != ESCAPE)) - { - status_mesg (mesg_type_1, mesg_type_2); - ch = wgetch (win[STA].p); - ch = toupper (ch); - } - if (ch == ESCAPE) - { + 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; - } - else - { - type = recur_char2def (ch); - } - - 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); - (void)wgetch (win[STA].p); - } - user_input[0] = '\0'; + } + + 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; + lt = localtime(&t); + 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; - } - - while (!date_entered) - { - (void)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 && strncmp (user_input, "0", 1) == 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; - lt = localtime (&t); - 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); - (void)wgetch (win[STA].p); - date_entered = 0; - } - else - { - date_entered = 1; - } - } - else - { - (void)snprintf (outstr, BUFSIZ, mesg_wrong_2, - DATEFMT_DESC (conf->input_datefmt)); - status_mesg (mesg_wrong_1, _(outstr)); - (void)wgetch (win[STA].p); - date_entered = 0; - } - } - } - else - return; - } - - date = calendar_get_slctd_day_sec (); - if (p->type == EVNT) - { - (void)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_KEEP_NOTE); + } + } 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); } /* * Read days for which recurrent items must not be repeated * (such days are called exceptions). */ -void -recur_exc_scan (llist_t *lexc, FILE *data_file) +void recur_exc_scan(llist_t * lexc, FILE * data_file) { int c = 0; struct tm day; - LLIST_INIT (lexc); - while ((c = getc (data_file)) == '!') - { - (void)ungetc (c, data_file); - if (fscanf (data_file, "!%u / %u / %u ", - &day.tm_mon, &day.tm_mday, &day.tm_year) != 3) - { - EXIT (_("syntax error in item date")); - } - day.tm_hour = 12; - day.tm_min = day.tm_sec = 0; - day.tm_isdst = -1; - day.tm_year -= 1900; - day.tm_mon--; - struct excp *exc = mem_malloc (sizeof (struct excp)); - exc->st = mktime (&day); - LLIST_ADD (lexc, exc); + LLIST_INIT(lexc); + while ((c = getc(data_file)) == '!') { + ungetc(c, data_file); + if (fscanf(data_file, "!%d / %d / %d ", + &day.tm_mon, &day.tm_mday, &day.tm_year) != 3) { + EXIT(_("syntax error in item date")); } + day.tm_hour = 0; + day.tm_min = day.tm_sec = 0; + day.tm_isdst = -1; + day.tm_year -= 1900; + day.tm_mon--; + struct excp *exc = mem_malloc(sizeof(struct excp)); + exc->st = mktime(&day); + LLIST_ADD(lexc, exc); + } } -static int -recur_apoint_starts_before (struct recur_apoint *rapt, long time) +static int recur_apoint_starts_before(struct recur_apoint *rapt, long time) { - return (rapt->start < time); + return rapt->start < time; } /* * Look in the appointment list if we have an item which starts before the item * stored in the notify_app structure (which is the next item to be notified). */ -struct notify_app * -recur_apoint_check_next (struct notify_app *app, long start, long day) +struct notify_app *recur_apoint_check_next(struct notify_app *app, long start, + long day) { llist_item_t *i; - long real_recur_start_time; - - LLIST_TS_LOCK (&recur_alist_p); - LLIST_TS_FIND_FOREACH (&recur_alist_p, app->time, recur_apoint_starts_before, i) - { - struct recur_apoint *rapt = LLIST_TS_GET_DATA (i); - - real_recur_start_time = recur_apoint_inday(rapt, day); - if (real_recur_start_time > start) - { - app->time = real_recur_start_time; - app->txt = mem_strdup (rapt->mesg); - app->state = rapt->state; - app->got_app = 1; - } + unsigned real_recur_start_time; + + LLIST_TS_LOCK(&recur_alist_p); + LLIST_TS_FIND_FOREACH(&recur_alist_p, app->time, recur_apoint_starts_before, + i) { + struct recur_apoint *rapt = LLIST_TS_GET_DATA(i); + + if (recur_apoint_find_occurrence(rapt, day, &real_recur_start_time) && + real_recur_start_time > start) { + app->time = real_recur_start_time; + app->txt = mem_strdup(rapt->mesg); + app->state = rapt->state; + app->got_app = 1; } - LLIST_TS_UNLOCK (&recur_alist_p); + } + LLIST_TS_UNLOCK(&recur_alist_p); - return (app); + return app; } /* Returns a structure containing the selected recurrent appointment. */ -struct recur_apoint * -recur_get_apoint (long date, int num) +struct recur_apoint *recur_get_apoint(long date, int num) { - llist_item_t *i = LLIST_TS_FIND_NTH (&recur_alist_p, num, date, + llist_item_t *i = LLIST_TS_FIND_NTH(&recur_alist_p, num, date, recur_apoint_inday); if (i) - return LLIST_TS_GET_DATA (i); + return LLIST_TS_GET_DATA(i); - EXIT (_("item not found")); + EXIT(_("item not found")); /* NOTREACHED */ } /* Returns a structure containing the selected recurrent event. */ -struct recur_event * -recur_get_event (long date, int num) +struct recur_event *recur_get_event(long date, int num) { - llist_item_t *i = LLIST_FIND_NTH (&recur_elist, num, date, - recur_event_inday); + llist_item_t *i = LLIST_FIND_NTH(&recur_elist, num, date, + recur_event_inday); if (i) - return LLIST_GET_DATA (i); + return LLIST_GET_DATA(i); - EXIT (_("item not found")); + 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(long date, int recur_nb) { llist_item_t *i; - LLIST_TS_LOCK (&recur_alist_p); - i = LLIST_TS_FIND_NTH (&recur_alist_p, recur_nb, date, recur_apoint_inday); + 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); + EXIT(_("item not found")); + struct recur_apoint *rapt = LLIST_TS_GET_DATA(i); rapt->state ^= APOINT_NOTIFY; - if (notify_bar ()) - notify_check_repeated (rapt); + if (notify_bar()) + notify_check_repeated(rapt); - LLIST_TS_UNLOCK (&recur_alist_p); + LLIST_TS_UNLOCK(&recur_alist_p); } -void -recur_event_paste_item (void) +void recur_event_paste_item(void) { long new_start, time_shift; llist_item_t *i; - new_start = date2sec (*calendar_get_slctd_day (), 12, 0); + new_start = date2sec(*calendar_get_slctd_day(), 0, 0); time_shift = new_start - bkp_cut_recur_event.day; 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) - { - struct excp *exc = LLIST_GET_DATA (i); - exc->st += time_shift; - } - - (void)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 (ERASE_FORCE_KEEP_NOTE); + LLIST_FOREACH(&bkp_cut_recur_event.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(); } -void -recur_apoint_paste_item (void) +void recur_apoint_paste_item(void) { long new_start, 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)); + 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; 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) - { - struct excp *exc = LLIST_GET_DATA (i); - exc->st += time_shift; - } + LLIST_FOREACH(&bkp_cut_recur_event.exc, i) { + struct excp *exc = LLIST_GET_DATA(i); + exc->st += time_shift; + } - (void)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); + 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); - if (notify_bar ()) - notify_check_repeated (&bkp_cut_recur_apoint); + if (notify_bar()) + notify_check_repeated(&bkp_cut_recur_apoint); - recur_apoint_free_bkp (ERASE_FORCE_KEEP_NOTE); + recur_apoint_free_bkp(); } diff --git a/src/sha1.c b/src/sha1.c new file mode 100644 index 0000000..4fbf245 --- /dev/null +++ b/src/sha1.c @@ -0,0 +1,267 @@ +/* + * 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 + * + * This code is based on Steve Reid's public domain SHA1 implementation. + * + * The original version is available at: + * ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c + * + */ + +#include <stdio.h> +#include <string.h> + +#include "sha1.h" + +#define rol(val, n) (((val) << (n)) | ((val) >> (32 - (n)))) + +#ifdef WORDS_BIGENDIAN +#define blk0(i) block->l[i] +#else +#define blk0(i) (block->l[i] = (rol (block->l[i], 24) & \ + (uint32_t)0xFF00FF00) | (rol (block->l[i], 8) & (uint32_t)0x00FF00FF)) +#endif + +#define blk(i) (block->l[i & 15] = rol (block->l[(i + 13) & 15] ^ \ + block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +#define R0(v, w, x, y, z, i) z += ((w & (x ^ y)) ^ y) + blk0 (i) + \ + 0x5A827999 + rol (v, 5); w = rol (w, 30); +#define R1(v, w, x, y, z, i) z += ((w & (x ^ y)) ^ y) + blk (i) + \ + 0x5A827999 + rol (v, 5); w = rol (w, 30); +#define R2(v, w, x, y, z, i) z += (w ^ x ^ y) + blk (i) + 0x6ED9EBA1 + \ + rol (v, 5); w = rol(w, 30); +#define R3(v, w, x, y, z, i) z += (((w | x) & y) | (w & x)) + blk (i) + \ + 0x8F1BBCDC + rol (v, 5); w = rol (w, 30); +#define R4(v, w, x, y, z, i) z += (w ^ x ^ y) + blk (i) + 0xCA62C1D6 + \ + rol (v, 5); w = rol (w, 30); + +static void sha1_transform(uint32_t state[5], const uint8_t buffer[64]) +{ + typedef union { + uint8_t c[64]; + uint32_t l[16]; + } b64_t; + + b64_t *block = (b64_t *) buffer; + uint32_t a = state[0]; + uint32_t b = state[1]; + uint32_t c = state[2]; + uint32_t d = state[3]; + uint32_t e = state[4]; + + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + a = b = c = d = e = 0; +} + +void sha1_init(sha1_ctx_t * ctx) +{ + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + + ctx->count[0] = ctx->count[1] = 0; +} + +void sha1_update(sha1_ctx_t * ctx, const uint8_t * data, unsigned int len) +{ + unsigned int i, j; + + j = (ctx->count[0] >> 3) & 63; + if ((ctx->count[0] += len << 3) < (len << 3)) + ctx->count[1]++; + ctx->count[1] += (len >> 29); + + if (j + len > 63) { + memcpy(&ctx->buffer[j], data, (i = 64 - j)); + sha1_transform(ctx->state, ctx->buffer); + for (; i + 63 < len; i += 64) + sha1_transform(ctx->state, &data[i]); + j = 0; + } else + i = 0; + memcpy(&ctx->buffer[j], &data[i], len - i); +} + +void sha1_final(sha1_ctx_t * ctx, uint8_t digest[SHA1_DIGESTLEN]) +{ + uint32_t i, j; + uint8_t finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (uint8_t) ((ctx->count[(i >= 4 ? 0 : 1)] >> + ((3 - (i & 3)) * 8)) & 255); + } + + sha1_update(ctx, (uint8_t *) "\200", 1); + while ((ctx->count[0] & 504) != 448) + sha1_update(ctx, (uint8_t *) "\0", 1); + + sha1_update(ctx, finalcount, 8); + for (i = 0; i < SHA1_DIGESTLEN; i++) + digest[i] = (uint8_t) ((ctx->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + + i = j = 0; + memset(ctx->buffer, 0, SHA1_BLOCKLEN); + memset(ctx->state, 0, SHA1_DIGESTLEN); + memset(ctx->count, 0, 8); + memset(&finalcount, 0, 8); +} + +void sha1_digest(const char *data, char *buffer) +{ + sha1_ctx_t ctx; + uint8_t digest[SHA1_DIGESTLEN]; + int i; + + sha1_init(&ctx); + sha1_update(&ctx, (const uint8_t *)data, strlen(data)); + sha1_final(&ctx, (uint8_t *) digest); + + for (i = 0; i < SHA1_DIGESTLEN; i++) { + snprintf(buffer, 3, "%02x", digest[i]); + buffer += sizeof(char) * 2; + } +} + +void sha1_stream(FILE * fp, char *buffer) +{ + sha1_ctx_t ctx; + uint8_t data[BUFSIZ]; + size_t bytes_read; + uint8_t digest[SHA1_DIGESTLEN]; + int i; + + sha1_init(&ctx); + + while (!feof(fp)) { + bytes_read = fread(data, 1, BUFSIZ, fp); + sha1_update(&ctx, data, bytes_read); + } + + sha1_final(&ctx, (uint8_t *) digest); + + for (i = 0; i < SHA1_DIGESTLEN; i++) { + snprintf(buffer, 3, "%02x", digest[i]); + buffer += sizeof(char) * 2; + } +} diff --git a/src/sha1.h b/src/sha1.h new file mode 100644 index 0000000..8f90ff5 --- /dev/null +++ b/src/sha1.h @@ -0,0 +1,57 @@ +/* + * 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 + * + * This code is based on Steve Reid's public domain SHA1 implementation. + * + * The original version is available at: + * ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c + * + */ + +#include <stdint.h> + +#define SHA1_BLOCKLEN 64 +#define SHA1_DIGESTLEN 20 + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + uint8_t buffer[SHA1_BLOCKLEN]; +} sha1_ctx_t; + +void sha1_init(sha1_ctx_t *); +void sha1_update(sha1_ctx_t *, const uint8_t *, unsigned int); +void sha1_final(sha1_ctx_t *, uint8_t *); +void sha1_digest(const char *, char *); +void sha1_stream(FILE *, char *); @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -43,63 +43,58 @@ #include "calcurse.h" +#ifndef WAIT_MYPGRP +#define WAIT_MYPGRP 0 +#endif + /* * General signal handling routine. * Catch return values from children (user-defined notification commands). * This is needed to avoid zombie processes running on system. * Also catch CTRL-C (SIGINT), and SIGWINCH to resize screen automatically. */ -static void -generic_hdlr (int sig) +static void generic_hdlr(int sig) { - switch (sig) - { - case SIGCHLD: - while (waitpid (WAIT_MYPGRP, NULL, WNOHANG) > 0) - ; - break; - case SIGWINCH: - resize = 1; - clearok (curscr, TRUE); - (void)ungetch (KEY_RESIZE); - break; - case SIGTERM: - if (unlink (path_cpid) != 0) - { - EXIT (_("Could not remove calcurse lock file: %s\n"), - strerror (errno)); - } - exit (EXIT_SUCCESS); - break; + switch (sig) { + case SIGCHLD: + while (waitpid(WAIT_MYPGRP, NULL, WNOHANG) > 0) ; + break; + case SIGWINCH: + resize = 1; + clearok(curscr, TRUE); + ungetch(KEY_RESIZE); + break; + case SIGTERM: + if (unlink(path_cpid) != 0) { + EXIT(_("Could not remove calcurse lock file: %s\n"), strerror(errno)); } + exit(EXIT_SUCCESS); + break; + } } -unsigned -sigs_set_hdlr (int sig, void (*handler)(int)) +unsigned sigs_set_hdlr(int sig, void (*handler) (int)) { struct sigaction sa; - memset (&sa, 0, sizeof sa); - sigemptyset (&sa.sa_mask); + memset(&sa, 0, sizeof sa); + sigemptyset(&sa.sa_mask); sa.sa_handler = handler; sa.sa_flags = 0; - if (sigaction (sig, &sa, (struct sigaction *)0) == -1) - { - ERROR_MSG (_("Error setting signal #%d : %s\n"), - sig, strerror (errno)); - return 0; - } + if (sigaction(sig, &sa, NULL) == -1) { + ERROR_MSG(_("Error setting signal #%d : %s\n"), sig, strerror(errno)); + return 0; + } return 1; } /* Signal handling init. */ -void -sigs_init () +void sigs_init() { - if (!sigs_set_hdlr (SIGCHLD, generic_hdlr) - || !sigs_set_hdlr (SIGWINCH, generic_hdlr) - || !sigs_set_hdlr (SIGTERM, generic_hdlr) - || !sigs_set_hdlr (SIGINT, SIG_IGN)) - exit_calcurse (1); + if (!sigs_set_hdlr(SIGCHLD, generic_hdlr) + || !sigs_set_hdlr(SIGWINCH, generic_hdlr) + || !sigs_set_hdlr(SIGTERM, generic_hdlr) + || !sigs_set_hdlr(SIGINT, SIG_IGN)) + exit_calcurse(1); } @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -47,171 +47,161 @@ static int first = 1; static char *msgsav; /* Returns a structure containing the selected item. */ -static struct todo * -todo_get_item (int item_number) +static struct todo *todo_get_item(int item_number) { - return LLIST_GET_DATA (LLIST_NTH (&todolist, item_number - 1)); + return LLIST_GET_DATA(LLIST_NTH(&todolist, item_number - 1)); } /* Sets which todo is highlighted. */ -void -todo_hilt_set (int highlighted) +void todo_hilt_set(int highlighted) { hilt = highlighted; } -void -todo_hilt_decrease (void) +void todo_hilt_decrease(int n) { - hilt--; + hilt -= n; } -void -todo_hilt_increase (void) +void todo_hilt_increase(int n) { - hilt++; + hilt += n; } /* Return which todo is highlighted. */ -int -todo_hilt (void) +int todo_hilt(void) { - return (hilt); + return hilt; } /* Return the number of todos. */ -int -todo_nb (void) +int todo_nb(void) { - return (todos); + return todos; } /* Set the number of todos. */ -void -todo_set_nb (int nb) +void todo_set_nb(int nb) { todos = nb; } /* Set which one is the first todo to be displayed. */ -void -todo_set_first (int nb) +void todo_set_first(int nb) { first = nb; } -void -todo_first_increase (void) +void todo_first_increase(int n) { - first++; + first += n; } -void -todo_first_decrease (void) +void todo_first_decrease(int n) { - first--; + first -= n; } /* * Return the position of the hilghlighted item, relative to the first one * displayed. */ -int -todo_hilt_pos (void) +int todo_hilt_pos(void) { - return (hilt - first); + return hilt - first; } /* Return the last visited todo. */ -char * -todo_saved_mesg (void) +char *todo_saved_mesg(void) { - return (msgsav); + return msgsav; } /* Request user to enter a new todo item. */ -void -todo_new_item (void) +void todo_new_item(void) { int ch = 0; - char *mesg = _("Enter the new ToDo item : "); - char *mesg_id = _("Enter the ToDo priority [1 (highest) - 9 (lowest)] :"); + 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++; + 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) +static int todo_cmp_id(struct todo *a, struct todo *b) { /* * As of version 2.6, todo items can have a negative id, which means they * were completed. To keep them sorted, we need to consider the absolute id * value. */ - int abs_a = abs (a->id); - int abs_b = abs (b->id); + int abs_a = abs(a->id); + int abs_b = abs(b->id); - return (abs_a < abs_b ? -1 : (abs_a == abs_b ? 0 : 1)); + return abs_a < abs_b ? -1 : (abs_a == abs_b ? 0 : 1); } /* * Add an item in the todo linked list. */ -struct todo * -todo_add (char *mesg, int id, char *note) +struct todo *todo_add(char *mesg, int id, char *note) { struct todo *todo; - todo = mem_malloc (sizeof (struct todo)); - todo->mesg = mem_strdup (mesg); + todo = mem_malloc(sizeof(struct todo)); + todo->mesg = mem_strdup(mesg); todo->id = id; - todo->note = (note != NULL && note[0] != '\0') ? mem_strdup (note) : NULL; + todo->note = (note != NULL && note[0] != '\0') ? mem_strdup(note) : NULL; - LLIST_ADD_SORTED (&todolist, todo, todo_cmp_id); + LLIST_ADD_SORTED(&todolist, todo, todo_cmp_id); return todo; } +void todo_write(struct todo *todo, FILE * f) +{ + if (todo->note) + fprintf(f, "[%d]>%s %s\n", todo->id, todo->note, todo->mesg); + else + fprintf(f, "[%d] %s\n", todo->id, todo->mesg); +} + /* Delete a note previously attached to a todo item. */ -static void -todo_delete_note_bynum (unsigned num) +static void todo_delete_note_bynum(unsigned num) { - llist_item_t *i = LLIST_NTH (&todolist, num); + llist_item_t *i = LLIST_NTH(&todolist, num); if (!i) - EXIT (_("no such todo")); - struct todo *todo = LLIST_TS_GET_DATA (i); + EXIT(_("no such todo")); + struct todo *todo = LLIST_TS_GET_DATA(i); if (!todo->note) - EXIT (_("no note attached")); - erase_note (&todo->note, ERASE_FORCE_ONLY_NOTE); + EXIT(_("no note attached")); + erase_note(&todo->note); } /* Delete an item from the todo linked list. */ -static void -todo_delete_bynum (unsigned num, enum eraseflg flag) +static void todo_delete_bynum(unsigned num) { - llist_item_t *i = LLIST_NTH (&todolist, num); + llist_item_t *i = LLIST_NTH(&todolist, num); if (!i) - EXIT (_("no such todo")); - struct todo *todo = LLIST_TS_GET_DATA (i); + EXIT(_("no such todo")); + struct todo *todo = LLIST_TS_GET_DATA(i); - LLIST_REMOVE (&todolist, i); - mem_free (todo->mesg); - erase_note (&todo->note, flag); - mem_free (todo); + LLIST_REMOVE(&todolist, i); + mem_free(todo->mesg); + erase_note(&todo->note); + mem_free(todo); } /* @@ -220,186 +210,164 @@ todo_delete_bynum (unsigned num, enum eraseflg flag) * 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(void) { struct todo *t; - t = todo_get_item (hilt); + t = todo_get_item(hilt); t->id = -t->id; } /* Delete an item from the ToDo list. */ -void -todo_delete (struct conf *conf) +void todo_delete(void) { - char *choices = "[y/n] "; - char *del_todo_str = _("Do you really want to delete this task ?"); - char *erase_warning = + 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 ?"); - char *erase_choice = _("[t/n] "); - unsigned go_for_todo_del = 0; - int answer, has_note; - - if (conf->confirm_delete) - { - status_mesg (del_todo_str, choices); - answer = wgetch (win[STA].p); - if ((answer == 'y') && (todos > 0)) - { - go_for_todo_del = 1; - } - else - { - wins_erase_status_bar (); - return; - } - } - else if (todos > 0) - go_for_todo_del = 1; - - if (go_for_todo_del == 0) - { - wins_erase_status_bar (); - return; - } - - answer = -1; - has_note = (todo_get_item (hilt)->note != NULL) ? 1 : 0; - if (has_note == 0) - answer = 't'; + const char *erase_choice = _("[tn]"); + const int nb_erase_choice = 2; + int answer; - while (answer != 't' && answer != 'n' && answer != KEY_GENERIC_CANCEL) - { - status_mesg (erase_warning, erase_choice); - answer = wgetch (win[STA].p); - } + if ((todos <= 0) || + (conf.confirm_delete && (status_ask_bool(del_todo_str) != 1))) { + wins_erase_status_bar(); + return; + } - switch (answer) - { - case 't': - todo_delete_bynum (hilt - 1, ERASE_FORCE); - todos--; - if (hilt > 1) - hilt--; - if (todos == 0) - hilt = 0; - if (hilt - first < 0) - first--; - break; - case 'n': - todo_delete_note_bynum (hilt - 1); - break; - default: - 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. */ -static int -todo_get_position (struct todo *needle) +static int todo_get_position(struct todo *needle) { llist_item_t *i; int n = 0; - LLIST_FOREACH (&todolist, i) - { - n++; - if (LLIST_TS_GET_DATA (i) == needle) - return n; - } + LLIST_FOREACH(&todolist, i) { + n++; + if (LLIST_TS_GET_DATA(i) == needle) + return n; + } - EXIT (_("todo not found")); - return -1; /* avoid compiler warnings */ + EXIT(_("todo not found")); + return -1; /* avoid compiler warnings */ } /* Change an item priority by pressing '+' or '-' inside TODO panel. */ -void -todo_chg_priority (int action) +void todo_chg_priority(int action) { struct todo *backup; char backup_mesg[BUFSIZ]; int backup_id; - char backup_note[NOTESIZ + 1]; - int do_chg = 1; + char backup_note[MAX_NOTESIZ + 1]; - backup = todo_get_item (hilt); - (void)strncpy (backup_mesg, backup->mesg, strlen (backup->mesg) + 1); + backup = todo_get_item(hilt); + strncpy(backup_mesg, backup->mesg, strlen(backup->mesg) + 1); backup_id = backup->id; if (backup->note) - (void)strncpy (backup_note, backup->note, NOTESIZ + 1); + strncpy(backup_note, backup->note, MAX_NOTESIZ + 1); else backup_note[0] = '\0'; - switch (action) - { - case KEY_RAISE_PRIORITY: - (backup_id > 1) ? backup_id-- : do_chg--; - break; - case KEY_LOWER_PRIORITY: - (backup_id > 0 && backup_id < 9) ? backup_id++ : do_chg--; - break; - default: - EXIT (_("no such action")); - /* NOTREACHED */ - } - if (do_chg) - { - todo_delete_bynum (hilt - 1, ERASE_FORCE_KEEP_NOTE); - backup = todo_add (backup_mesg, backup_id, backup_note); - hilt = todo_get_position (backup); - } + 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 = 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) +void todo_edit_item(void) { struct todo *i; - char *mesg = _("Enter the new ToDo description :"); + const char *mesg = _("Enter the new ToDo description :"); - status_mesg (mesg, ""); - i = todo_get_item (hilt); - updatestring (win[STA].p, &i->mesg, 0, 1); + 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 len, int y, - int x) +display_todo_item(int incolor, char *msg, int prio, int note, int width, int y, + int x) { WINDOW *w; int ch_note; - char buf[len], priostr[2]; + char buf[width * UTF8_MAXLEN], priostr[2]; + int i; w = win[TOD].p; ch_note = (note) ? '>' : '.'; if (prio > 0) - snprintf (priostr, sizeof priostr, "%d", prio); + snprintf(priostr, sizeof priostr, "%d", prio); else - snprintf (priostr, sizeof priostr, "X"); + strncpy(priostr, "X", sizeof priostr); if (incolor == 0) - custom_apply_attr (w, ATTR_HIGHEST); - if (strlen (msg) < len) - mvwprintw (w, y, x, "%s%c %s", priostr, ch_note, msg); - else - { - (void)strncpy (buf, msg, len - 1); - buf[len - 1] = '\0'; - mvwprintw (w, y, x, "%s%c %s...", priostr, ch_note, buf); + custom_apply_attr(w, ATTR_HIGHEST); + if (utf8_strwidth(msg) < width) + mvwprintw(w, y, x, "%s%c %s", priostr, ch_note, msg); + else { + for (i = 0; msg[i] && width > 0; i++) { + if (!UTF8_ISCONT(msg[i])) + width -= utf8_width(&msg[i]); + buf[i] = msg[i]; } + if (i) + buf[i - 1] = 0; + else + buf[0] = 0; + mvwprintw(w, y, x, "%s%c %s...", priostr, ch_note, buf); + } if (incolor == 0) - custom_remove_attr (w, ATTR_HIGHEST); + custom_remove_attr(w, ATTR_HIGHEST); } /* Updates the ToDo panel. */ -void -todo_update_panel (int which_pan) +void todo_update_panel(int which_pan) { llist_item_t *i; int len = win[TOD].w - 8; @@ -412,97 +380,94 @@ todo_update_panel (int which_pan) int incolor = -1; /* 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) - { - struct todo *todo = LLIST_TS_GET_DATA (i); - num_todo++; - t_realpos = num_todo - first; - incolor = num_todo - hilt; - if (incolor == 0) - msgsav = todo->mesg; - if (t_realpos >= 0 && t_realpos < max_items) - { - display_todo_item (incolor, todo->mesg, todo->id, - (todo->note != NULL) ? 1 : 0, len, y_offset, - x_offset); - y_offset = y_offset + todo_lines; - } + erase_window_part(win[TOD].p, 1, title_lines, win[TOD].w - 2, win[TOD].h - 2); + LLIST_FOREACH(&todolist, i) { + struct todo *todo = LLIST_TS_GET_DATA(i); + num_todo++; + t_realpos = num_todo - first; + incolor = (which_pan == TOD) ? num_todo - hilt : num_todo; + if (incolor == 0) + msgsav = todo->mesg; + if (t_realpos >= 0 && t_realpos < max_items) { + display_todo_item(incolor, todo->mesg, todo->id, + (todo->note != NULL) ? 1 : 0, len, y_offset, x_offset); + y_offset = y_offset + todo_lines; } + } /* 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); - unsigned hilt_bar = (which_pan == TOD) ? 1 : 0; - int sbar_top = highend + title_lines; - - if ((sbar_top + sbar_length) > win[TOD].h - 1) - sbar_length = win[TOD].h - 1 - sbar_top; - draw_scrollbar (win[TOD].p, sbar_top, win[TOD].w - 2, - sbar_length, title_lines, win[TOD].h - 1, hilt_bar); - } - - wnoutrefresh (win[TOD].p); + if (todos > max_items) { + float ratio = ((float)max_items) / ((float)todos); + int sbar_length = (int)(ratio * (max_items + 1)); + int highend = (int)(ratio * first); + unsigned hilt_bar = (which_pan == TOD) ? 1 : 0; + int sbar_top = highend + title_lines; + + if ((sbar_top + sbar_length) > win[TOD].h - 1) + sbar_length = win[TOD].h - 1 - sbar_top; + draw_scrollbar(win[TOD].p, sbar_top, win[TOD].w - 2, + sbar_length, title_lines, win[TOD].h - 1, hilt_bar); + } + + wnoutrefresh(win[TOD].p); } /* Attach a note to a todo */ -void -todo_edit_note (char *editor) +void todo_edit_note(const char *editor) { - struct todo *i; - char fullname[BUFSIZ]; - char *filename; - - i = todo_get_item (hilt); - if (i->note == NULL) - { - if ((filename = new_tempfile (path_notes, NOTESIZ)) != NULL) - i->note = filename; - else - return; - } - (void)snprintf (fullname, BUFSIZ, "%s%s", path_notes, i->note); - wins_launch_external (fullname, editor); - - if (io_file_is_empty (fullname) > 0) - erase_note (&i->note, ERASE_FORCE); + struct todo *i = todo_get_item(hilt); + edit_note(&i->note, editor); } /* View a note previously attached to a todo */ -void -todo_view_note (char *pager) +void todo_view_note(const char *pager) { - struct todo *i; - char fullname[BUFSIZ]; + struct todo *i = todo_get_item(hilt); + view_note(i->note, pager); +} - i = todo_get_item (hilt); - if (i->note == NULL) +/* 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; - (void)snprintf (fullname, BUFSIZ, "%s%s", path_notes, i->note); - wins_launch_external (fullname, pager); + + 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(); } -void -todo_free (struct todo *todo) +static void todo_free(struct todo *todo) { - mem_free (todo->mesg); - erase_note (&todo->note, ERASE_FORCE_KEEP_NOTE); - mem_free (todo); + mem_free(todo->mesg); + erase_note(&todo->note); + mem_free(todo); } -void -todo_init_list (void) +void todo_init_list(void) { - LLIST_INIT (&todolist); + LLIST_INIT(&todolist); } -void -todo_free_list (void) +void todo_free_list(void) { - LLIST_FREE_INNER (&todolist, todo_free); - LLIST_FREE (&todolist); + LLIST_FREE_INNER(&todolist, todo_free); + LLIST_FREE(&todolist); } diff --git a/src/utf8.c b/src/utf8.c new file mode 100644 index 0000000..398b142 --- /dev/null +++ b/src/utf8.c @@ -0,0 +1,335 @@ +/* + * 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 utf8_range { + int min, max, width; +}; + +static const struct utf8_range utf8_widthtab[] = { + {0x00300, 0x0036f, 0}, + {0x00483, 0x00489, 0}, + {0x00591, 0x005bd, 0}, + {0x005bf, 0x005bf, 0}, + {0x005c1, 0x005c2, 0}, + {0x005c4, 0x005c5, 0}, + {0x005c7, 0x005c7, 0}, + {0x00610, 0x0061a, 0}, + {0x0064b, 0x0065e, 0}, + {0x00670, 0x00670, 0}, + {0x006d6, 0x006dc, 0}, + {0x006de, 0x006e4, 0}, + {0x006e7, 0x006e8, 0}, + {0x006ea, 0x006ed, 0}, + {0x00711, 0x00711, 0}, + {0x00730, 0x0074a, 0}, + {0x007a6, 0x007b0, 0}, + {0x007eb, 0x007f3, 0}, + {0x00816, 0x00819, 0}, + {0x0081b, 0x00823, 0}, + {0x00825, 0x00827, 0}, + {0x00829, 0x0082d, 0}, + {0x00900, 0x00903, 0}, + {0x0093c, 0x0093c, 0}, + {0x0093e, 0x0094e, 0}, + {0x00951, 0x00955, 0}, + {0x00962, 0x00963, 0}, + {0x00981, 0x00983, 0}, + {0x009bc, 0x009bc, 0}, + {0x009be, 0x009c4, 0}, + {0x009c7, 0x009c8, 0}, + {0x009cb, 0x009cd, 0}, + {0x009d7, 0x009d7, 0}, + {0x009e2, 0x009e3, 0}, + {0x00a01, 0x00a03, 0}, + {0x00a3c, 0x00a3c, 0}, + {0x00a3e, 0x00a42, 0}, + {0x00a47, 0x00a48, 0}, + {0x00a4b, 0x00a4d, 0}, + {0x00a51, 0x00a51, 0}, + {0x00a70, 0x00a71, 0}, + {0x00a75, 0x00a75, 0}, + {0x00a81, 0x00a83, 0}, + {0x00abc, 0x00abc, 0}, + {0x00abe, 0x00ac5, 0}, + {0x00ac7, 0x00ac9, 0}, + {0x00acb, 0x00acd, 0}, + {0x00ae2, 0x00ae3, 0}, + {0x00b01, 0x00b03, 0}, + {0x00b3c, 0x00b3c, 0}, + {0x00b3e, 0x00b44, 0}, + {0x00b47, 0x00b48, 0}, + {0x00b4b, 0x00b4d, 0}, + {0x00b56, 0x00b57, 0}, + {0x00b62, 0x00b63, 0}, + {0x00b82, 0x00b82, 0}, + {0x00bbe, 0x00bc2, 0}, + {0x00bc6, 0x00bc8, 0}, + {0x00bca, 0x00bcd, 0}, + {0x00bd7, 0x00bd7, 0}, + {0x00c01, 0x00c03, 0}, + {0x00c3e, 0x00c44, 0}, + {0x00c46, 0x00c48, 0}, + {0x00c4a, 0x00c4d, 0}, + {0x00c55, 0x00c56, 0}, + {0x00c62, 0x00c63, 0}, + {0x00c82, 0x00c83, 0}, + {0x00cbc, 0x00cbc, 0}, + {0x00cbe, 0x00cc4, 0}, + {0x00cc6, 0x00cc8, 0}, + {0x00cca, 0x00ccd, 0}, + {0x00cd5, 0x00cd6, 0}, + {0x00ce2, 0x00ce3, 0}, + {0x00d02, 0x00d03, 0}, + {0x00d3e, 0x00d44, 0}, + {0x00d46, 0x00d48, 0}, + {0x00d4a, 0x00d4d, 0}, + {0x00d57, 0x00d57, 0}, + {0x00d62, 0x00d63, 0}, + {0x00d82, 0x00d83, 0}, + {0x00dca, 0x00dca, 0}, + {0x00dcf, 0x00dd4, 0}, + {0x00dd6, 0x00dd6, 0}, + {0x00dd8, 0x00ddf, 0}, + {0x00df2, 0x00df3, 0}, + {0x00e31, 0x00e31, 0}, + {0x00e34, 0x00e3a, 0}, + {0x00e47, 0x00e4e, 0}, + {0x00eb1, 0x00eb1, 0}, + {0x00eb4, 0x00eb9, 0}, + {0x00ebb, 0x00ebc, 0}, + {0x00ec8, 0x00ecd, 0}, + {0x00f18, 0x00f19, 0}, + {0x00f35, 0x00f35, 0}, + {0x00f37, 0x00f37, 0}, + {0x00f39, 0x00f39, 0}, + {0x00f3e, 0x00f3f, 0}, + {0x00f71, 0x00f84, 0}, + {0x00f86, 0x00f87, 0}, + {0x00f90, 0x00f97, 0}, + {0x00f99, 0x00fbc, 0}, + {0x00fc6, 0x00fc6, 0}, + {0x0102b, 0x0103e, 0}, + {0x01056, 0x01059, 0}, + {0x0105e, 0x01060, 0}, + {0x01062, 0x01064, 0}, + {0x01067, 0x0106d, 0}, + {0x01071, 0x01074, 0}, + {0x01082, 0x0108d, 0}, + {0x0108f, 0x0108f, 0}, + {0x0109a, 0x0109d, 0}, + {0x01100, 0x0115f, 2}, + {0x011a3, 0x011a7, 2}, + {0x011fa, 0x011ff, 2}, + {0x0135f, 0x0135f, 0}, + {0x01712, 0x01714, 0}, + {0x01732, 0x01734, 0}, + {0x01752, 0x01753, 0}, + {0x01772, 0x01773, 0}, + {0x017b6, 0x017d3, 0}, + {0x017dd, 0x017dd, 0}, + {0x0180b, 0x0180d, 0}, + {0x018a9, 0x018a9, 0}, + {0x01920, 0x0192b, 0}, + {0x01930, 0x0193b, 0}, + {0x019b0, 0x019c0, 0}, + {0x019c8, 0x019c9, 0}, + {0x01a17, 0x01a1b, 0}, + {0x01a55, 0x01a5e, 0}, + {0x01a60, 0x01a7c, 0}, + {0x01a7f, 0x01a7f, 0}, + {0x01b00, 0x01b04, 0}, + {0x01b34, 0x01b44, 0}, + {0x01b6b, 0x01b73, 0}, + {0x01b80, 0x01b82, 0}, + {0x01ba1, 0x01baa, 0}, + {0x01c24, 0x01c37, 0}, + {0x01cd0, 0x01cd2, 0}, + {0x01cd4, 0x01ce8, 0}, + {0x01ced, 0x01ced, 0}, + {0x01cf2, 0x01cf2, 0}, + {0x01dc0, 0x01de6, 0}, + {0x01dfd, 0x01dff, 0}, + {0x020d0, 0x020f0, 0}, + {0x02329, 0x0232a, 2}, + {0x02cef, 0x02cf1, 0}, + {0x02de0, 0x02dff, 0}, + {0x02e80, 0x02e99, 2}, + {0x02e9b, 0x02ef3, 2}, + {0x02f00, 0x02fd5, 2}, + {0x02ff0, 0x02ffb, 2}, + {0x03000, 0x03029, 2}, + {0x0302a, 0x0302f, 0}, + {0x03030, 0x0303e, 2}, + {0x03041, 0x03096, 2}, + {0x03099, 0x0309a, 0}, + {0x0309b, 0x030ff, 2}, + {0x03105, 0x0312d, 2}, + {0x03131, 0x0318e, 2}, + {0x03190, 0x031b7, 2}, + {0x031c0, 0x031e3, 2}, + {0x031f0, 0x0321e, 2}, + {0x03220, 0x03247, 2}, + {0x03250, 0x032fe, 2}, + {0x03300, 0x04dbf, 2}, + {0x04e00, 0x0a48c, 2}, + {0x0a490, 0x0a4c6, 2}, + {0x0a66f, 0x0a672, 0}, + {0x0a67c, 0x0a67d, 0}, + {0x0a6f0, 0x0a6f1, 0}, + {0x0a802, 0x0a802, 0}, + {0x0a806, 0x0a806, 0}, + {0x0a80b, 0x0a80b, 0}, + {0x0a823, 0x0a827, 0}, + {0x0a880, 0x0a881, 0}, + {0x0a8b4, 0x0a8c4, 0}, + {0x0a8e0, 0x0a8f1, 0}, + {0x0a926, 0x0a92d, 0}, + {0x0a947, 0x0a953, 0}, + {0x0a960, 0x0a97c, 2}, + {0x0a980, 0x0a983, 0}, + {0x0a9b3, 0x0a9c0, 0}, + {0x0aa29, 0x0aa36, 0}, + {0x0aa43, 0x0aa43, 0}, + {0x0aa4c, 0x0aa4d, 0}, + {0x0aa7b, 0x0aa7b, 0}, + {0x0aab0, 0x0aab0, 0}, + {0x0aab2, 0x0aab4, 0}, + {0x0aab7, 0x0aab8, 0}, + {0x0aabe, 0x0aabf, 0}, + {0x0aac1, 0x0aac1, 0}, + {0x0abe3, 0x0abea, 0}, + {0x0abec, 0x0abed, 0}, + {0x0ac00, 0x0d7a3, 2}, + {0x0d7b0, 0x0d7c6, 2}, + {0x0d7cb, 0x0d7fb, 2}, + {0x0f900, 0x0faff, 2}, + {0x0fb1e, 0x0fb1e, 0}, + {0x0fe00, 0x0fe0f, 0}, + {0x0fe10, 0x0fe19, 2}, + {0x0fe20, 0x0fe26, 0}, + {0x0fe30, 0x0fe52, 2}, + {0x0fe54, 0x0fe66, 2}, + {0x0fe68, 0x0fe6b, 2}, + {0x0ff01, 0x0ff60, 2}, + {0x0ffe0, 0x0ffe6, 2}, + {0x101fd, 0x101fd, 0}, + {0x10a01, 0x10a03, 0}, + {0x10a05, 0x10a06, 0}, + {0x10a0c, 0x10a0f, 0}, + {0x10a38, 0x10a3a, 0}, + {0x10a3f, 0x10a3f, 0}, + {0x11080, 0x11082, 0}, + {0x110b0, 0x110ba, 0}, + {0x1d165, 0x1d169, 0}, + {0x1d16d, 0x1d172, 0}, + {0x1d17b, 0x1d182, 0}, + {0x1d185, 0x1d18b, 0}, + {0x1d1aa, 0x1d1ad, 0}, + {0x1d242, 0x1d244, 0}, + {0x1f200, 0x1f200, 2}, + {0x1f210, 0x1f231, 2}, + {0x1f240, 0x1f248, 2}, + {0x20000, 0x2fffd, 2}, + {0x30000, 0x3fffd, 2}, + {0xe0100, 0xe01ef, 0} +}; + +/* Get the width of a UTF-8 character. */ +int utf8_width(char *s) +{ + int val, low, high, cur; + + if (UTF8_ISCONT(*s)) + return 0; + + switch (UTF8_LENGTH(*s)) { + case 1: + val = s[0]; + break; + case 2: + val = (s[1] & 0x3f) | (s[0] & 0x1f) << 6; + break; + case 3: + val = ((s[2] & 0x3f) | (s[1] & 0x3f) << 6) | (s[0] & 0x0f) << 12; + break; + case 4: + val = (((s[3] & 0x3f) | (s[2] & 0x3f) << 6) | + (s[1] & 0x3f) << 12) | (s[0] & 0x3f) << 18; + break; + case 5: + val = ((((s[4] & 0x3f) | (s[3] & 0x3f) << 6) | + (s[2] & 0x3f) << 12) | (s[1] & 0x3f) << 18) | (s[0] & 0x3f) << 24; + break; + case 6: + val = (((((s[5] & 0x3f) | (s[4] & 0x3f) << 6) | + (s[3] & 0x3f) << 12) | (s[2] & 0x3f) << 18) | + (s[1] & 0x3f) << 24) | (s[0] & 0x3f) << 30; + break; + default: + return 0; + } + + low = 0; + high = sizeof(utf8_widthtab) / sizeof(utf8_widthtab[0]); + do { + cur = (low + high) / 2; + if (val >= utf8_widthtab[cur].min) { + if (val <= utf8_widthtab[cur].max) + return utf8_widthtab[cur].width; + else + low = cur + 1; + } else + high = cur - 1; + } + while (low <= high); + + return 1; +} + +/* Get the width of a UTF-8 string. */ +int utf8_strwidth(char *s) +{ + int width = 0; + + for (; s && *s; s++) { + if (!UTF8_ISCONT(*s)) + width += utf8_width(s); + } + + return width; +} diff --git a/src/utils.c b/src/utils.c index 0a01c2e..b3d9c71 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -42,69 +42,80 @@ #include <ctype.h> #include <sys/types.h> #include <errno.h> +#include <fcntl.h> +#include <sys/wait.h> +#include <termios.h> #include "calcurse.h" #define ISLEAP(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) +#define FS_EXT_MAXLEN 64 + +enum format_specifier { + FS_STARTDATE, + FS_DURATION, + FS_ENDDATE, + FS_MESSAGE, + FS_NOTE, + FS_NOTEFILE, + FS_PRIORITY, + FS_PSIGN, + FS_EOF, + FS_UNKNOWN +}; + /* General routine to exit calcurse properly. */ -void -exit_calcurse (int status) +void exit_calcurse(int status) { int was_interactive; - if (ui_mode == UI_CURSES) - { - notify_stop_main_thread (); - clear (); - wins_refresh (); - endwin (); - ui_mode = UI_CMDLINE; - was_interactive = 1; - } - else + if (ui_mode == UI_CURSES) { + notify_stop_main_thread(); + clear(); + wins_refresh(); + endwin(); + ui_mode = UI_CMDLINE; + was_interactive = 1; + } else was_interactive = 0; - calendar_stop_date_thread (); - io_stop_psave_thread (); - free_user_data (); - keys_free (); - mem_stats (); - if (was_interactive) - { - if (unlink (path_cpid) != 0) - EXIT (_("Could not remove calcurse lock file: %s\n"), - strerror (errno)); - if (dmon.enable) - dmon_start (status); - } + calendar_stop_date_thread(); + io_stop_psave_thread(); + free_user_data(); + keys_free(); + mem_stats(); + if (was_interactive) { + if (unlink(path_cpid) != 0) + EXIT(_("Could not remove calcurse lock file: %s\n"), strerror(errno)); + if (dmon.enable) + dmon_start(status); + } - exit (status); + exit(status); } -void -free_user_data (void) +void free_user_data(void) { - day_free_list (); - event_llist_free (); - event_free_bkp (ERASE_FORCE); - apoint_llist_free (); - apoint_free_bkp (ERASE_FORCE); - recur_apoint_llist_free (); - recur_event_llist_free (); - recur_apoint_free_bkp (ERASE_FORCE); - recur_event_free_bkp (ERASE_FORCE); - todo_free_list (); - notify_free_app (); + 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(); + todo_free_list(); + notify_free_app(); } /* Function to exit on internal error. */ -void -fatalbox (const char *errmsg) +void fatalbox(const char *errmsg) { WINDOW *errwin; - char *label = _("/!\\ INTERNAL ERROR /!\\"); - char *reportmsg = _("Please report the following bug:"); + const char *label = _("/!\\ INTERNAL ERROR /!\\"); + const char *reportmsg = _("Please report the following bug:"); const int WINROW = 10; const int WINCOL = col - 2; const int MSGLEN = WINCOL - 2; @@ -113,25 +124,24 @@ fatalbox (const char *errmsg) if (errmsg == NULL) return; - (void)strncpy (msg, errmsg, MSGLEN); - errwin = newwin (WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2); - custom_apply_attr (errwin, ATTR_HIGHEST); - box (errwin, 0, 0); - wins_show (errwin, label); - mvwprintw (errwin, 3, 1, reportmsg); - mvwprintw (errwin, 5, (WINCOL - strlen (msg)) / 2, "%s", msg); - custom_remove_attr (errwin, ATTR_HIGHEST); - wins_wrefresh (errwin); - (void)wgetch (errwin); - delwin (errwin); - wins_doupdate (); + strncpy(msg, errmsg, MSGLEN); + errwin = newwin(WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2); + custom_apply_attr(errwin, ATTR_HIGHEST); + box(errwin, 0, 0); + wins_show(errwin, label); + mvwprintw(errwin, 3, 1, reportmsg); + mvwprintw(errwin, 5, (WINCOL - strlen(msg)) / 2, "%s", msg); + custom_remove_attr(errwin, ATTR_HIGHEST); + wins_wrefresh(errwin); + wgetch(errwin); + delwin(errwin); + wins_doupdate(); } -void -warnbox (const char *msg) +void warnbox(const char *msg) { WINDOW *warnwin; - char *label = "/!\\"; + const char *label = "/!\\"; const int WINROW = 10; const int WINCOL = col - 2; const int MSGLEN = WINCOL - 2; @@ -140,317 +150,208 @@ warnbox (const char *msg) if (msg == NULL) return; - (void)strncpy (displmsg, msg, MSGLEN); - warnwin = newwin (WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2); - custom_apply_attr (warnwin, ATTR_HIGHEST); - box (warnwin, 0, 0); - wins_show (warnwin, label); - mvwprintw (warnwin, 5, (WINCOL - strlen (displmsg)) / 2, "%s", displmsg); - custom_remove_attr (warnwin, ATTR_HIGHEST); - wins_wrefresh (warnwin); - (void)wgetch (warnwin); - delwin (warnwin); - wins_doupdate (); + strncpy(displmsg, msg, MSGLEN); + warnwin = newwin(WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2); + custom_apply_attr(warnwin, ATTR_HIGHEST); + box(warnwin, 0, 0); + wins_show(warnwin, label); + mvwprintw(warnwin, 5, (WINCOL - strlen(displmsg)) / 2, "%s", displmsg); + custom_remove_attr(warnwin, ATTR_HIGHEST); + wins_wrefresh(warnwin); + wgetch(warnwin); + delwin(warnwin); + wins_doupdate(); } /* * Print a message in the status bar. * Message texts for first line and second line are to be provided. */ -void -status_mesg (char *mesg_line1, char *mesg_line2) +void status_mesg(const char *msg1, const char *msg2) { - wins_erase_status_bar (); - custom_apply_attr (win[STA].p, ATTR_HIGHEST); - mvwprintw (win[STA].p, 0, 0, mesg_line1); - mvwprintw (win[STA].p, 1, 0, mesg_line2); - custom_remove_attr (win[STA].p, ATTR_HIGHEST); + wins_erase_status_bar(); + custom_apply_attr(win[STA].p, ATTR_HIGHEST); + mvwprintw(win[STA].p, 0, 0, msg1); + mvwprintw(win[STA].p, 1, 0, msg2); + custom_remove_attr(win[STA].p, ATTR_HIGHEST); +} + +/* + * Prompts the user to make a choice between named alternatives. + * + * The available choices are described by a string of the form + * "[ynp]". The first and last char are ignored (they are only here to + * make the translators' life easier), and every other char indicates + * a key the user is allowed to press. + * + * Returns the index of the key pressed by the user (starting from 1), + * or -1 if the user doesn't want to answer (e.g. by escaping). + */ +int status_ask_choice(const char *message, const char choice[], int nb_choice) +{ + int i, ch; + char tmp[BUFSIZ]; + /* "[4/2/f/t/w/.../Z] " */ + char avail_choice[2 * nb_choice + 3]; + + avail_choice[0] = '['; + avail_choice[1] = '\0'; + + for (i = 1; i <= nb_choice; i++) { + snprintf(tmp, BUFSIZ, (i == nb_choice) ? "%c] " : "%c/", choice[i]); + strcat(avail_choice, tmp); + } + + status_mesg(message, avail_choice); + + for (;;) { + ch = wgetch(win[STA].p); + for (i = 1; i <= nb_choice; i++) + if (ch == choice[i]) + return i; + if (ch == ESCAPE) + return (-1); + if (resize) { + resize = 0; + wins_reset(); + status_mesg(message, avail_choice); + } + } +} + +/* + * Prompts the user with a boolean question. + * + * Returns 1 if yes, 2 if no, and -1 otherwise + */ +int status_ask_bool(const char *msg) +{ + return (status_ask_choice(msg, _("[yn]"), 2)); +} + +/* + * Prompts the user to make a choice between a number of alternatives. + * + * Returns the option chosen by the user (starting from 1), or -1 if + * the user doesn't want to answer. + */ +int +status_ask_simplechoice(const char *prefix, const char *choice[], int nb_choice) +{ + int i; + char tmp[BUFSIZ]; + /* "(1) Choice1, (2) Choice2, (3) Choice3?" */ + char choicestr[BUFSIZ]; + /* Holds the characters to choose from ('1', '2', etc) */ + char char_choice[nb_choice + 2]; + + /* No need to initialize first and last char. */ + for (i = 1; i <= nb_choice; i++) + char_choice[i] = '0' + i; + + strcpy(choicestr, prefix); + + for (i = 0; i < nb_choice; i++) { + snprintf(tmp, BUFSIZ, ((i + 1) == nb_choice) ? "(%d) %s?" : "(%d) %s, ", + (i + 1), _(choice[i])); + strcat(choicestr, tmp); + } + + return (status_ask_choice(choicestr, char_choice, nb_choice)); } /* Erase part of a window. */ void -erase_window_part (WINDOW *win, int first_col, int first_row, int last_col, - int last_row) +erase_window_part(WINDOW * win, int first_col, int first_row, int last_col, + int last_row) { int c, r; - for (r = first_row; r <= last_row; r++) - { - for (c = first_col; c <= last_col; c++) - mvwprintw (win, r, c, " "); - } - - wnoutrefresh (win); + for (r = first_row; r <= last_row; r++) { + for (c = first_col; c <= last_col; c++) + mvwprintw(win, r, c, " "); + } } /* draws a popup window */ -WINDOW * -popup (int pop_row, int pop_col, int pop_y, int pop_x, char *title, char *msg, - int hint) +WINDOW *popup(int pop_row, int pop_col, int pop_y, int pop_x, const char *title, + const char *msg, int hint) { - char *any_key = _("Press any key to continue..."); + const char *any_key = _("Press any key to continue..."); char label[BUFSIZ]; WINDOW *popup_win; const int MSGXPOS = 5; - popup_win = newwin (pop_row, pop_col, pop_y, pop_x); - keypad (popup_win, TRUE); + popup_win = newwin(pop_row, pop_col, pop_y, pop_x); + keypad(popup_win, TRUE); if (msg) - mvwprintw (popup_win, MSGXPOS, (pop_col - strlen (msg)) / 2, "%s", msg); - custom_apply_attr (popup_win, ATTR_HIGHEST); - box (popup_win, 0, 0); - (void)snprintf (label, BUFSIZ, "%s", title); - wins_show (popup_win, label); + mvwprintw(popup_win, MSGXPOS, (pop_col - strlen(msg)) / 2, "%s", msg); + custom_apply_attr(popup_win, ATTR_HIGHEST); + box(popup_win, 0, 0); + snprintf(label, BUFSIZ, "%s", title); + wins_show(popup_win, label); if (hint) - mvwprintw (popup_win, pop_row - 2, pop_col - (strlen (any_key) + 1), "%s", - any_key); - custom_remove_attr (popup_win, ATTR_HIGHEST); - wins_wrefresh (popup_win); + mvwprintw(popup_win, pop_row - 2, pop_col - (strlen(any_key) + 1), "%s", + any_key); + custom_remove_attr(popup_win, ATTR_HIGHEST); + wins_wrefresh(popup_win); return popup_win; } /* prints in middle of a panel */ void -print_in_middle (WINDOW *win, int starty, int startx, int width, char *string) +print_in_middle(WINDOW * win, int starty, int startx, int width, + const char *string) { - int len = strlen (string); + int len = strlen(string); int x, y; win = win ? win : stdscr; - getyx (win, y, x); + getyx(win, y, x); x = startx ? startx : x; y = starty ? starty : y; width = width ? width : 80; x += (width - len) / 2; - custom_apply_attr (win, ATTR_HIGHEST); - mvwprintw (win, y, x, "%s", string); - custom_remove_attr (win, ATTR_HIGHEST); -} - -/* Print the string at the desired position. */ -static void -showstring (WINDOW *win, int x, int y, char *str, int len, int scroff, - int curpos) -{ - char c = 0; - - /* print string */ - mvwaddnstr (win, y, x, &str[scroff], -1); - wclrtoeol (win); - - /* print scrolling indicator */ - if (scroff > 0 && scroff < len - col) - c = '*'; - else if (scroff > 0) - c = '<'; - else if (scroff < len - col) - c = '>'; - mvwprintw (win, y, col - 1, "%c", c); - - /* print cursor */ - wmove (win, y, curpos - scroff); - - if (curpos >= len) - waddch (win, SPACE | A_REVERSE); - else - waddch (win, str[curpos] | A_REVERSE); -} - -/* Delete a character at the given position in string. */ -static void -del_char (int pos, char *str) -{ - str += pos; - memmove (str, str + 1, strlen (str) + 1); -} - -/* Add a character at the given position in string. */ -static void -ins_char (int pos, int ch, char *str) -{ - str += pos; - memmove (str + 1, str, strlen (str) + 1); - *str = ch; -} - -static void -bell (void) -{ - printf ("\a"); -} - -/* - * Getstring allows to get user input and to print it on a window, - * even if noecho() is on. This function is also used to modify an existing - * text (the variable string can be non-NULL). - * We need to do the echoing manually because of the multi-threading - * environment, otherwise the cursor would move from place to place without - * control. - */ -enum getstr -getstring (WINDOW *win, char *str, int l, int x, int y) -{ - const int pgsize = col / 3; - - int len = strlen (str); - int curpos = len; - int scroff = 0; - int ch; - - custom_apply_attr (win, ATTR_HIGHEST); - - for (;;) { - while (curpos < scroff) - scroff -= pgsize; - while (curpos >= scroff + col - 1) - scroff += pgsize; - - showstring (win, x, y, str, len, scroff, curpos); - wins_doupdate (); - - if ((ch = wgetch (win)) == '\n') break; - switch (ch) - { - case KEY_BACKSPACE: /* delete one character */ - case 330: - case 127: - case CTRL ('H'): - if (curpos > 0) - { - del_char ((--curpos), str); - len--; - } - else - bell (); - break; - case CTRL ('D'): /* delete next character */ - if (curpos < len) - { - del_char (curpos, str); - len--; - } - else - bell (); - break; - case CTRL ('W'): /* delete a word */ - if (curpos > 0) { - while (curpos && str[curpos - 1] == ' ') - { - del_char ((--curpos), str); - len--; - } - while (curpos && str[curpos - 1] != ' ') - { - del_char ((--curpos), str); - len--; - } - } - else - bell (); - break; - case CTRL ('K'): /* delete to end-of-line */ - str[curpos] = 0; - len = curpos; - break; - case CTRL ('A'): /* go to begginning of string */ - curpos = 0; - break; - case CTRL ('E'): /* go to end of string */ - curpos = len; - break; - case KEY_LEFT: /* move one char backward */ - case CTRL ('B'): - if (curpos > 0) curpos--; - break; - case KEY_RIGHT: /* move one char forward */ - case CTRL ('F'): - if (curpos < len) curpos++; - break; - case ESCAPE: /* cancel editing */ - return (GETSTRING_ESC); - break; - default: /* insert one character */ - if (len < l - 1) - { - ins_char ((curpos++), ch, str); - len++; - } - } - } - - custom_remove_attr (win, ATTR_HIGHEST); - - return (len == 0 ? GETSTRING_RET : GETSTRING_VALID); -} - -/* Update an already existing string. */ -int -updatestring (WINDOW *win, char **str, int x, int y) -{ - int len = strlen (*str); - char *buf; - enum getstr ret; - - EXIT_IF (len + 1 > BUFSIZ, _("Internal error: line too long")); - - buf = mem_malloc (BUFSIZ); - (void)memcpy (buf, *str, len + 1); - - ret = getstring (win, buf, BUFSIZ, x, y); - - if (ret == GETSTRING_VALID) - { - len = strlen (buf); - *str = mem_realloc (*str, len + 1, 1); - EXIT_IF (*str == NULL, _("out of memory")); - (void)memcpy (*str, buf, len + 1); - } - - mem_free (buf); - return ret; + custom_apply_attr(win, ATTR_HIGHEST); + mvwprintw(win, y, x, "%s", string); + custom_remove_attr(win, ATTR_HIGHEST); } /* checks if a string is only made of digits */ -int -is_all_digit (char *string) +int is_all_digit(const char *string) { - for (; *string; string++) - { - if (!isdigit ((int)*string)) - return 0; - } + for (; *string; string++) { + if (!isdigit((int)*string)) + return 0; + } return 1; } /* Given an item date expressed in seconds, return its start time in seconds. */ -long -get_item_time (long date) +long get_item_time(long date) { - return (long)(get_item_hour (date) * HOURINSEC + - get_item_min (date) * MININSEC); + return (long)(get_item_hour(date) * HOURINSEC + + get_item_min(date) * MININSEC); } -int -get_item_hour (long date) +int get_item_hour(long date) { - return (localtime ((time_t *)&date))->tm_hour; + return (localtime((time_t *) & date))->tm_hour; } -int -get_item_min (long date) +int get_item_min(long date) { - return (localtime ((time_t *)&date))->tm_min; + return (localtime((time_t *) & date))->tm_min; } -long -date2sec (struct date day, unsigned hour, unsigned min) +long date2sec(struct date day, unsigned hour, unsigned min) { - time_t t = now (); - struct tm start = *(localtime (&t)); + time_t t = now(); + struct tm start = *(localtime(&t)); start.tm_mon = day.mm - 1; start.tm_mday = day.dd; @@ -460,40 +361,37 @@ date2sec (struct date day, unsigned hour, unsigned min) start.tm_sec = 0; start.tm_isdst = -1; - t = mktime (&start); - EXIT_IF (t == -1, _("failure in mktime")); + t = mktime(&start); + EXIT_IF(t == -1, _("failure in mktime")); return t; } /* Return a string containing the date, given a date in seconds. */ -char * -date_sec2date_str (long sec, char *datefmt) +char *date_sec2date_str(long sec, const char *datefmt) { struct tm *lt; - char *datestr = (char *) mem_calloc (BUFSIZ, sizeof (char)); + char *datestr = (char *)mem_calloc(BUFSIZ, sizeof(char)); if (sec == 0) - (void)snprintf (datestr, BUFSIZ, "0"); - else - { - lt = localtime ((time_t *)&sec); - strftime (datestr, BUFSIZ, datefmt, lt); - } + strncpy(datestr, "0", BUFSIZ); + else { + lt = localtime((time_t *) & sec); + strftime(datestr, BUFSIZ, datefmt, lt); + } return datestr; } /* Generic function to format date. */ -void -date_sec2date_fmt (long sec, const char *fmt, char *datef) +void date_sec2date_fmt(long sec, const char *fmt, char *datef) { /* TODO: Find a better way to deal with localization and strftime(). */ char *locale_old = mem_strdup (setlocale (LC_ALL, NULL)); setlocale (LC_ALL, "C"); - struct tm *lt = localtime ((time_t *)&sec); - strftime (datef, BUFSIZ, fmt, lt); + struct tm *lt = localtime((time_t *)&sec); + strftime(datef, BUFSIZ, fmt, lt); setlocale (LC_ALL, locale_old); mem_free (locale_old); @@ -502,19 +400,18 @@ date_sec2date_fmt (long sec, const char *fmt, char *datef) /* * Used to change date by adding a certain amount of days or weeks. */ -long -date_sec_change (long date, int delta_month, int delta_day) +long date_sec_change(long date, int delta_month, int delta_day) { struct tm *lt; time_t t; t = date; - lt = localtime (&t); + lt = localtime(&t); lt->tm_mon += delta_month; lt->tm_mday += delta_day; lt->tm_isdst = -1; - t = mktime (lt); - EXIT_IF (t == -1, _("failure in mktime")); + t = mktime(lt); + EXIT_IF(t == -1, _("failure in mktime")); return t; } @@ -523,28 +420,26 @@ date_sec_change (long date, int delta_month, int delta_day) * Return a long containing the date which is updated taking into account * the new time and date entered by the user. */ -long -update_time_in_date (long date, unsigned hr, unsigned mn) +long update_time_in_date(long date, unsigned hr, unsigned mn) { struct tm *lt; time_t t, new_date; t = date; - lt = localtime (&t); + lt = localtime(&t); lt->tm_hour = hr; lt->tm_min = mn; - new_date = mktime (lt); - EXIT_IF (new_date == -1, _("error in mktime")); + new_date = mktime(lt); + EXIT_IF(new_date == -1, _("error in mktime")); - return (new_date); + return new_date; } /* * Returns the date in seconds from year 1900. * If no date is entered, current date is chosen. */ -long -get_sec_date (struct date date) +long get_sec_date(struct date date) { struct tm *ptrtime; time_t timer; @@ -553,56 +448,23 @@ get_sec_date (struct date date) char current_month[] = "mm "; char current_year[] = "yyyy "; - if (date.yyyy == 0 && date.mm == 0 && date.dd == 0) - { - timer = time (NULL); - ptrtime = localtime (&timer); - strftime (current_day, strlen (current_day), "%d", ptrtime); - strftime (current_month, strlen (current_month), "%m", ptrtime); - strftime (current_year, strlen (current_year), "%Y", ptrtime); - date.mm = atoi (current_month); - date.dd = atoi (current_day); - date.yyyy = atoi (current_year); - } - long_date = date2sec (date, 0, 0); - return (long_date); + if (date.yyyy == 0 && date.mm == 0 && date.dd == 0) { + timer = time(NULL); + ptrtime = localtime(&timer); + strftime(current_day, strlen(current_day), "%d", ptrtime); + strftime(current_month, strlen(current_month), "%m", ptrtime); + strftime(current_year, strlen(current_year), "%Y", ptrtime); + date.mm = atoi(current_month); + date.dd = atoi(current_day); + date.yyyy = atoi(current_year); + } + long_date = date2sec(date, 0, 0); + return long_date; } -long -min2sec (unsigned minutes) +long min2sec(unsigned minutes) { - return (minutes * MININSEC); -} - -/* - * Checks if a time has a good format. - * The format could be either HH:MM or H:MM or MM, and we should have: - * 0 <= HH <= 24 and 0 <= MM < 999. - * This function returns 1 if the entered time is correct and in - * [h:mm] or [hh:mm] format, and 2 if the entered time is correct and entered - * in [mm] format. - */ -int -check_time (char *string) -{ - char *s = mem_strdup(string); - char *hour = strtok(s, ":"); - char *min = strtok(NULL, ":"); - int h, m; - int ret = 0; - - if (min) - { - h = atoi (hour); - m = atoi (min); - if (h >= 0 && h < 24 && m >= 0 && m < MININSEC) - ret = 1; - } - else if (strlen(s) < 4 && is_all_digit(s) && atoi(s) > 0) - ret = 2; - - mem_free(s); - return ret; + return minutes * MININSEC; } /* @@ -610,17 +472,17 @@ check_time (char *string) * can not be displayed inside the corresponding panel. */ void -draw_scrollbar (WINDOW *win, int y, int x, int length, - int bar_top, int bar_bottom, unsigned hilt) +draw_scrollbar(WINDOW * win, int y, int x, int length, + int bar_top, int bar_bottom, unsigned hilt) { - mvwvline (win, bar_top, x, ACS_VLINE, bar_bottom - bar_top); + mvwvline(win, bar_top, x, ACS_VLINE, bar_bottom - bar_top); if (hilt) - custom_apply_attr (win, ATTR_HIGHEST); - wattron (win, A_REVERSE); - mvwvline (win, y, x, ' ', length); - wattroff (win, A_REVERSE); + custom_apply_attr(win, ATTR_HIGHEST); + wattron(win, A_REVERSE); + mvwvline(win, y, x, ' ', length); + wattroff(win, A_REVERSE); if (hilt) - custom_remove_attr (win, ATTR_HIGHEST); + custom_remove_attr(win, ATTR_HIGHEST); } /* @@ -629,121 +491,112 @@ draw_scrollbar (WINDOW *win, int y, int x, int length, * long to fit in its corresponding panel window. */ void -item_in_popup (char *saved_a_start, char *saved_a_end, char *msg, - char *pop_title) +item_in_popup(const char *saved_a_start, const char *saved_a_end, + const char *msg, const char *pop_title) { WINDOW *popup_win, *pad; const int margin_left = 4, margin_top = 4; const int winl = row - 5, winw = col - margin_left; const int padl = winl - 2, padw = winw - margin_left; - pad = newpad (padl, padw); - popup_win = popup (winl, winw, 1, 2, pop_title, (char *)0, 1); - if (strncmp (pop_title, _("Appointment"), 11) == 0) - { - mvwprintw (popup_win, margin_top, margin_left, "- %s -> %s", - saved_a_start, saved_a_end); - } - mvwprintw (pad, 0, margin_left, "%s", msg); - wmove (win[STA].p, 0, 0); - pnoutrefresh (pad, 0, 0, margin_top + 2, margin_left, padl, winw); - wins_doupdate (); - (void)wgetch (popup_win); - delwin (pad); - delwin (popup_win); + 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); + } + mvwprintw(pad, 0, margin_left, "%s", msg); + wmove(win[STA].p, 0, 0); + pnoutrefresh(pad, 0, 0, margin_top + 2, margin_left, padl, winw); + wins_doupdate(); + wgetch(popup_win); + delwin(pad); + delwin(popup_win); } /* Returns the beginning of current day in seconds from 1900. */ -long -get_today (void) +long get_today(void) { struct tm *lt; time_t current_time; long current_day; struct date day; - current_time = time (NULL); - lt = localtime (¤t_time); + current_time = time(NULL); + lt = localtime(¤t_time); day.mm = lt->tm_mon + 1; day.dd = lt->tm_mday; day.yyyy = lt->tm_year + 1900; - current_day = date2sec (day, 0, 0); + current_day = date2sec(day, 0, 0); - return (current_day); + return current_day; } /* Returns the current time in seconds. */ -long -now (void) +long now(void) { - return (long)time (NULL); + return (long)time(NULL); } -char * -nowstr (void) +char *nowstr(void) { static char buf[BUFSIZ]; - time_t t = now (); + time_t t = now(); - (void)strftime (buf, sizeof buf, "%a %b %d %T %Y", localtime (&t)); + strftime(buf, sizeof buf, "%a %b %d %T %Y", localtime(&t)); return buf; } -long -mystrtol (const char *str) +long mystrtol(const char *str) { char *ep; long lval; errno = 0; - lval = strtol (str, &ep, 10); + lval = strtol(str, &ep, 10); if (str[0] == '\0' || *ep != '\0') - EXIT (_("could not convert string")); + EXIT(_("could not convert string")); if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) - EXIT (_("out of range")); + EXIT(_("out of range")); - return (lval); + return lval; } /* Print the given option value with appropriate color. */ void -print_bool_option_incolor (WINDOW *win, unsigned option, int pos_y, int pos_x) +print_bool_option_incolor(WINDOW * win, unsigned option, int pos_y, int pos_x) { int color = 0; - char option_value[BUFSIZ] = ""; - - if (option == 1) - { - color = ATTR_TRUE; - strncpy (option_value, _("yes"), BUFSIZ); - } - else if (option == 0) - { - color = ATTR_FALSE; - strncpy (option_value, _("no"), BUFSIZ); - } - else - EXIT (_("option not defined")); - - custom_apply_attr (win, color); - mvwprintw (win, pos_y, pos_x, "%s", option_value); - custom_remove_attr (win, color); - wnoutrefresh (win); - wins_doupdate (); + const char *option_value; + + if (option == 1) { + color = ATTR_TRUE; + option_value = _("yes"); + } else if (option == 0) { + color = ATTR_FALSE; + option_value = _("no"); + } else + EXIT(_("option not defined")); + + custom_apply_attr(win, color); + mvwprintw(win, pos_y, pos_x, "%s", option_value); + custom_remove_attr(win, color); + wnoutrefresh(win); + wins_doupdate(); } - /* * Get the name of the default directory for temporary files. */ -const char * -get_tempdir (void) +const char *get_tempdir(void) { - if (getenv ("TMPDIR")) - return getenv ("TMPDIR"); + if (getenv("TMPDIR")) + return getenv("TMPDIR"); +#ifdef P_tmpdir else if (P_tmpdir) return P_tmpdir; +#endif else return "/tmp"; } @@ -752,53 +605,32 @@ get_tempdir (void) * Create a new unique file, and return a newly allocated string which contains * the random part of the file name. */ -char * -new_tempfile (const char *prefix, int trailing_len) +char *new_tempfile(const char *prefix, int trailing_len) { char fullname[BUFSIZ]; int prefix_len, fd; FILE *file; if (prefix == NULL) - return (NULL); + return NULL; - prefix_len = strlen (prefix); + prefix_len = strlen(prefix); if (prefix_len + trailing_len >= BUFSIZ) - return (NULL); - memcpy (fullname, prefix, prefix_len); - (void)memset (fullname + prefix_len, 'X', trailing_len); + return NULL; + memcpy(fullname, prefix, prefix_len); + memset(fullname + prefix_len, 'X', trailing_len); fullname[prefix_len + trailing_len] = '\0'; - if ((fd = mkstemp (fullname)) == -1 || (file = fdopen (fd, "w+")) == NULL) - { - if (fd != -1) - { - unlink (fullname); - close (fd); - } - ERROR_MSG (_("temporary file \"%s\" could not be created"), fullname); - return (char *)0; + if ((fd = mkstemp(fullname)) == -1 || (file = fdopen(fd, "w+")) == NULL) { + if (fd != -1) { + unlink(fullname); + close(fd); } - fclose (file); - - return mem_strdup (fullname + prefix_len); -} - -/* Erase a note previously attached to a todo, event or appointment. */ -void -erase_note (char **note, enum eraseflg flag) -{ - char fullname[BUFSIZ]; + ERROR_MSG(_("temporary file \"%s\" could not be created"), fullname); + return NULL; + } + fclose(file); - if (*note == NULL) - return; - if (flag != ERASE_FORCE_KEEP_NOTE) - { - (void)snprintf (fullname, BUFSIZ, "%s%s", path_notes, *note); - if (unlink (fullname) != 0) - EXIT (_("could not remove note")); - } - mem_free (*note); - *note = NULL; + return mem_strdup(fullname + prefix_len); } /* @@ -814,75 +646,68 @@ erase_note (char **note, enum eraseflg flag) * Returns 1 if sucessfully converted or 0 if the string is an invalid date. */ int -parse_date (char *date_string, enum datefmt datefmt, int *year, int *month, - int *day, struct date *slctd_date) +parse_date(const char *date_string, enum datefmt datefmt, int *year, + int *month, int *day, struct date *slctd_date) { - char sep = (datefmt == DATEFMT_ISO) ? '-' : '/'; - char *p; - int in[3] = {0, 0, 0}, n = 0; + const char sep = (datefmt == DATEFMT_ISO) ? '-' : '/'; + const char *p; + int in[3] = { 0, 0, 0 }, n = 0; int d, m, y; if (!date_string) return 0; /* parse string into in[], read up to three integers */ - for (p = date_string; *p; p++) - { - if (*p == sep) - { - if ((++n) > 2) - return 0; - } - else if ((*p >= '0') && (*p <= '9')) - in[n] = in[n] * 10 + (int)(*p - '0'); - else + for (p = date_string; *p; p++) { + if (*p == sep) { + if ((++n) > 2) return 0; - } + } else if ((*p >= '0') && (*p <= '9')) + in[n] = in[n] * 10 + (int)(*p - '0'); + else + return 0; + } if ((!slctd_date && n < 2) || in[n] == 0) return 0; /* convert into day, month and year, depending on the date format */ - switch (datefmt) - { - case DATEFMT_MMDDYYYY: - m = (n >= 1) ? in[0] : 0; - d = (n >= 1) ? in[1] : in[0]; - y = in[2]; - break; - case DATEFMT_DDMMYYYY: - d = in[0]; - m = in[1]; - y = in[2]; - break; - case DATEFMT_YYYYMMDD: - case DATEFMT_ISO: - y = (n >= 2) ? in[n - 2] : 0; - m = (n >= 1) ? in[n - 1] : 0; - d = in[n]; - break; - default: - return 0; - } + switch (datefmt) { + case DATEFMT_MMDDYYYY: + m = (n >= 1) ? in[0] : 0; + d = (n >= 1) ? in[1] : in[0]; + y = in[2]; + break; + case DATEFMT_DDMMYYYY: + d = in[0]; + m = in[1]; + y = in[2]; + break; + case DATEFMT_YYYYMMDD: + case DATEFMT_ISO: + y = (n >= 2) ? in[n - 2] : 0; + m = (n >= 1) ? in[n - 1] : 0; + d = in[n]; + break; + default: + return 0; + } - if (slctd_date) - { - if (y > 0 && y < 100) - { - /* convert "YY" format into "YYYY" */ - y += slctd_date->yyyy - slctd_date->yyyy % 100; - } - else if (n < 2) - { - /* set year and, optionally, month if short from is used */ - y = slctd_date->yyyy; - if (n < 1) m = slctd_date->mm; - } + if (slctd_date) { + if (y > 0 && y < 100) { + /* convert "YY" format into "YYYY" */ + y += slctd_date->yyyy - slctd_date->yyyy % 100; + } else if (n < 2) { + /* set year and, optionally, month if short from is used */ + y = slctd_date->yyyy; + if (n < 1) + m = slctd_date->mm; } + } /* check if date is valid, take leap years into account */ if (y < 1902 || y > 2037 || m < 1 || m > 12 || d < 1 || - d > days[m - 1] + (m == 2 && ISLEAP (y)) ? 1 : 0) + d > days[m - 1] + (m == 2 && ISLEAP(y)) ? 1 : 0) return 0; if (year) @@ -895,19 +720,142 @@ parse_date (char *date_string, enum datefmt datefmt, int *year, int *month, return 1; } -void -str_toupper (char *s) +/* + * Converts a time string into hours and minutes. Short forms like "23:" + * (23:00) or ":45" (0:45) are allowed. + * + * Returns 1 on success and 0 on failure. + */ +int parse_time(const char *string, unsigned *hour, unsigned *minute) +{ + const char *p; + unsigned in[2] = { 0, 0 }, n = 0; + + if (!string) + return 0; + + /* parse string into in[], read up to two integers */ + for (p = string; *p; p++) { + if (*p == ':') { + if ((++n) > 1) + return 0; + } else if ((*p >= '0') && (*p <= '9')) + in[n] = in[n] * 10 + (int)(*p - '0'); + else + return 0; + } + + if (n != 1 || in[0] >= DAYINHOURS || in[1] >= HOURINMIN) + return 0; + + *hour = in[0]; + *minute = in[1]; + return 1; +} + +/* + * Converts a duration string into minutes. + * + * Allowed formats (noted as regular expressions): + * + * - \d*:\d* + * - (\d*m|\d*h(|\d*m)|\d*d(|\d*m|\d*h(|\d*m))) + * - \d+ + * + * "\d" is used as a placeholder for "(0|1|2|3|4|5|6|7|8|9)". + * + * Returns 1 on success and 0 on failure. + */ +int parse_duration(const char *string, unsigned *duration) +{ + enum { + STATE_INITIAL, + STATE_HHMM_MM, + STATE_DDHHMM_HH, + STATE_DDHHMM_MM, + STATE_DONE + } state = STATE_INITIAL; + + const char *p; + unsigned in = 0; + unsigned dur = 0; + + if (!string || *string == '\0') + return 0; + + /* parse string using a simple state machine */ + for (p = string; *p; p++) { + if ((*p >= '0') && (*p <= '9')) { + if (state == STATE_DONE) + return 0; + else + in = in * 10 + (int)(*p - '0'); + } else { + switch (state) { + case STATE_INITIAL: + if (*p == ':') { + dur += in * HOURINMIN; + state = STATE_HHMM_MM; + } else if (*p == 'd') { + dur += in * DAYINMIN; + state = STATE_DDHHMM_HH; + } else if (*p == 'h') { + dur += in * HOURINMIN; + state = STATE_DDHHMM_MM; + } else if (*p == 'm') { + dur += in; + state = STATE_DONE; + } else + return 0; + break; + case STATE_DDHHMM_HH: + if (*p == 'h') { + dur += in * HOURINMIN; + state = STATE_DDHHMM_MM; + } else if (*p == 'm') { + dur += in; + state = STATE_DONE; + } else + return 0; + break; + case STATE_DDHHMM_MM: + if (*p == 'm') { + dur += in; + state = STATE_DONE; + } else + return 0; + break; + case STATE_HHMM_MM: + case STATE_DONE: + return 0; + break; + } + + in = 0; + } + } + + if ((state == STATE_HHMM_MM && in >= HOURINMIN) || + ((state == STATE_DDHHMM_HH || state == STATE_DDHHMM_MM) && in > 0)) + return 0; + + dur += in; + *duration = dur; + + return 1; +} + +void str_toupper(char *s) { if (!s) return; for (; *s; s++) - *s = toupper (*s); + *s = toupper(*s); } -void -file_close (FILE *f, const char *pos) +void file_close(FILE * f, const char *pos) { - EXIT_IF ((fclose (f)) != 0, _("Error when closing file at %s"), pos); + EXIT_IF((fclose(f)) != 0, _("Error when closing file at %s"), pos); } /* @@ -915,11 +863,482 @@ file_close (FILE *f, const char *pos) * (hence the 'p') in a way that even if a signal is caught during the sleep * process, this function will return to sleep afterwards. */ -void -psleep (unsigned secs) +void psleep(unsigned secs) { unsigned unslept; - for (unslept = sleep (secs); unslept; unslept = sleep (unslept)) - ; + for (unslept = sleep(secs); unslept; unslept = sleep(unslept)) ; +} + +/* + * Fork and execute an external process. + * + * If pfdin and/or pfdout point to a valid address, a pipe is created and the + * appropriate file descriptors are written to pfdin/pfdout. + */ +int fork_exec(int *pfdin, int *pfdout, const char *path, const char *const *arg) +{ + int pin[2], pout[2]; + int pid; + + if (pfdin && (pipe(pin) == -1)) + return 0; + if (pfdout && (pipe(pout) == -1)) + return 0; + + if ((pid = fork()) == 0) { + if (pfdout) { + if (dup2(pout[0], STDIN_FILENO) < 0) + _exit(127); + close(pout[0]); + close(pout[1]); + } + + if (pfdin) { + if (dup2(pin[1], STDOUT_FILENO) < 0) + _exit(127); + close(pin[0]); + close(pin[1]); + } + + execvp(path, (char *const *)arg); + _exit(127); + } else { + if (pfdin) + close(pin[1]); + if (pfdout) + close(pout[0]); + + if (pid > 0) { + if (pfdin) { + fcntl(pin[0], F_SETFD, FD_CLOEXEC); + *pfdin = pin[0]; + } + if (pfdout) { + fcntl(pout[1], F_SETFD, FD_CLOEXEC); + *pfdout = pout[1]; + } + } else { + if (pfdin) + close(pin[0]); + if (pfdout) + close(pout[1]); + return 0; + } + } + return pid; +} + +/* Execute an external program in a shell. */ +int +shell_exec(int *pfdin, int *pfdout, const char *path, const char *const *arg) +{ + int argc, i; + const char **narg; + char *arg0 = NULL; + int ret; + + for (argc = 0; arg[argc]; argc++) ; + + if (argc < 1) + return -1; + + narg = mem_calloc(argc + 4, sizeof(const char *)); + + narg[0] = "sh"; + narg[1] = "-c"; + + if (argc > 1) { + arg0 = mem_malloc(strlen(path) + 6); + sprintf(arg0, "%s \"$@\"", path); + narg[2] = arg0; + + for (i = 0; i < argc; i++) + narg[i + 3] = arg[i]; + narg[argc + 3] = NULL; + } else { + narg[2] = path; + narg[3] = NULL; + } + + ret = fork_exec(pfdin, pfdout, *narg, narg); + + if (arg0) + mem_free(arg0); + mem_free(narg); + + return ret; +} + +/* Wait for a child process to terminate. */ +int child_wait(int *pfdin, int *pfdout, int pid) +{ + int stat; + + if (pfdin) + close(*pfdin); + if (pfdout) + close(*pfdout); + + waitpid(pid, &stat, 0); + return stat; +} + +/* Display "Press any key to continue..." and wait for a key press. */ +void press_any_key(void) +{ + struct termios t_attr_old, t_attr; + + tcgetattr(STDIN_FILENO, &t_attr_old); + memcpy(&t_attr, &t_attr_old, sizeof(struct termios)); + t_attr.c_lflag &= ~(ICANON | ECHO | ECHONL); + tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_attr); + + fflush(stdout); + fputs(_("Press any key to continue..."), stdout); + fflush(stdout); + fgetc(stdin); + fflush(stdin); + fputs("\r\n", stdout); + + tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_attr_old); +} + +/* + * Display note contents if one is asociated with the currently displayed item + * (to be used together with the '-a' or '-t' flag in non-interactive mode). + * Each line begins with nbtab tabs. + * Print "No note file found", if the notefile does not exists. + * + * (patch submitted by Erik Saule). + */ +static void print_notefile(FILE * out, const char *filename, int nbtab) +{ + char path_to_notefile[BUFSIZ]; + FILE *notefile; + char linestarter[BUFSIZ]; + char buffer[BUFSIZ]; + int i; + int printlinestarter = 1; + + if (nbtab < BUFSIZ) { + for (i = 0; i < nbtab; i++) + linestarter[i] = '\t'; + linestarter[nbtab] = '\0'; + } else + linestarter[0] = '\0'; + + snprintf(path_to_notefile, BUFSIZ, "%s/%s", path_notes, filename); + notefile = fopen(path_to_notefile, "r"); + if (notefile) { + while (fgets(buffer, BUFSIZ, notefile) != 0) { + if (printlinestarter) { + fputs(linestarter, out); + printlinestarter = 0; + } + fputs(buffer, out); + if (buffer[strlen(buffer) - 1] == '\n') + printlinestarter = 1; + } + fputs("\n", out); + file_close(notefile, __FILE_POS__); + } else { + fputs(linestarter, out); + fputs(_("No note file found\n"), out); + } +} + +/* Print an escape sequence and return its length. */ +static int print_escape(const char *s) +{ + switch (*(s + 1)) { + case 'a': + putchar('\a'); + return 1; + case 'b': + putchar('\b'); + return 1; + case 'f': + putchar('\f'); + return 1; + case 'n': + putchar('\n'); + return 1; + case 'r': + putchar('\r'); + return 1; + case 't': + putchar('\t'); + return 1; + case 'v': + putchar('\v'); + return 1; + case '0': + putchar('\0'); + return 1; + case '\'': + putchar('\''); + return 1; + case '"': + putchar('"'); + return 1; + case '\?': + putchar('?'); + return 1; + case '\\': + putchar('\\'); + return 1; + case '\0': + return 0; + default: + return 1; + } +} + +/* Parse a format specifier. */ +static enum format_specifier parse_fs(const char **s, char *extformat) +{ + char buf[FS_EXT_MAXLEN]; + int i; + + extformat[0] = '\0'; + + switch (**s) { + case 's': + strcpy(extformat, "epoch"); + return FS_STARTDATE; + case 'S': + return FS_STARTDATE; + case 'd': + return FS_DURATION; + case 'e': + strcpy(extformat, "epoch"); + return FS_ENDDATE; + case 'E': + return FS_ENDDATE; + case 'm': + return FS_MESSAGE; + case 'n': + return FS_NOTE; + case 'N': + return FS_NOTEFILE; + case 'p': + return FS_PRIORITY; + case '(': + /* Long format specifier. */ + for ((*s)++, i = 0; **s != ':' && **s != ')'; (*s)++, i++) { + if (**s == '\0') + return FS_EOF; + + if (i < FS_EXT_MAXLEN) + buf[i] = **s; + } + + buf[(i < FS_EXT_MAXLEN) ? i : FS_EXT_MAXLEN - 1] = '\0'; + + if (**s == ':') { + for ((*s)++, i = 0; **s != ')'; (*s)++, i++) { + if (**s == '\0') + return FS_EOF; + + if (i < FS_EXT_MAXLEN) + extformat[i] = **s; + } + + extformat[(i < FS_EXT_MAXLEN) ? i : FS_EXT_MAXLEN - 1] = '\0'; + } + + if (!strcmp(buf, "start")) + return FS_STARTDATE; + else if (!strcmp(buf, "duration")) + return FS_DURATION; + else if (!strcmp(buf, "end")) + return FS_ENDDATE; + else if (!strcmp(buf, "message")) + return FS_MESSAGE; + else if (!strcmp(buf, "noteid")) + return FS_NOTE; + else if (!strcmp(buf, "note")) + return FS_NOTEFILE; + else if (!strcmp(buf, "priority")) + return FS_PRIORITY; + else + return FS_UNKNOWN; + case '%': + return FS_PSIGN; + case '\0': + return FS_EOF; + default: + return FS_UNKNOWN; + } +} + +/* Print a formatted date to stdout. */ +static void print_date(long date, long day, const char *extformat) +{ + char buf[BUFSIZ]; + + if (!strcmp(extformat, "epoch")) + printf("%ld", date); + else { + time_t t = date; + struct tm *lt = localtime((time_t *) & t); + + if (extformat[0] == '\0' || !strcmp(extformat, "default")) { + if (date >= day && date <= day + DAYINSEC) + strftime(buf, BUFSIZ, "%H:%M", lt); + else + strftime(buf, BUFSIZ, "..:..", lt); + } else { + strftime(buf, BUFSIZ, extformat, lt); + } + + printf("%s", buf); + } +} + +/* Print a formatted appointment to stdout. */ +void print_apoint(const char *format, long day, struct apoint *apt) +{ + const char *p; + char extformat[FS_EXT_MAXLEN]; + + for (p = format; *p; p++) { + if (*p == '%') { + p++; + switch (parse_fs(&p, extformat)) { + case FS_STARTDATE: + print_date(apt->start, day, extformat); + break; + case FS_DURATION: + printf("%ld", apt->dur); + break; + case FS_ENDDATE: + print_date(apt->start + apt->dur, day, extformat); + break; + case FS_MESSAGE: + printf("%s", apt->mesg); + break; + case FS_NOTE: + printf("%s", apt->note); + break; + case FS_NOTEFILE: + print_notefile(stdout, apt->note, 1); + break; + case FS_PSIGN: + putchar('%'); + break; + case FS_EOF: + return; + break; + default: + putchar('?'); + break; + } + } else if (*p == '\\') + p += print_escape(p); + else + putchar(*p); + } +} + +/* Print a formatted event to stdout. */ +void print_event(const char *format, long day, struct event *ev) +{ + const char *p; + char extformat[FS_EXT_MAXLEN]; + + for (p = format; *p; p++) { + if (*p == '%') { + p++; + switch (parse_fs(&p, extformat)) { + case FS_MESSAGE: + printf("%s", ev->mesg); + break; + case FS_NOTE: + printf("%s", ev->note); + break; + case FS_NOTEFILE: + print_notefile(stdout, ev->note, 1); + break; + case FS_PSIGN: + putchar('%'); + break; + case FS_EOF: + return; + break; + default: + putchar('?'); + break; + } + } else if (*p == '\\') + p += print_escape(p); + else + putchar(*p); + } +} + +/* Print a formatted recurrent appointment to stdout. */ +void +print_recur_apoint(const char *format, long day, unsigned occurrence, + struct recur_apoint *rapt) +{ + struct apoint apt; + + apt.start = occurrence; + apt.dur = rapt->dur; + apt.mesg = rapt->mesg; + apt.note = rapt->note; + + print_apoint(format, day, &apt); +} + +/* Print a formatted recurrent event to stdout. */ +void print_recur_event(const char *format, long day, struct recur_event *rev) +{ + struct event ev; + + ev.mesg = rev->mesg; + ev.note = rev->note; + + print_event(format, day, &ev); +} + +/* Print a formatted todo item to stdout. */ +void print_todo(const char *format, struct todo *todo) +{ + const char *p; + char extformat[FS_EXT_MAXLEN]; + + for (p = format; *p; p++) { + if (*p == '%') { + p++; + switch (parse_fs(&p, extformat)) { + case FS_PRIORITY: + printf("%d", abs(todo->id)); + break; + case FS_MESSAGE: + printf("%s", todo->mesg); + break; + case FS_NOTE: + printf("%s", todo->note); + break; + case FS_NOTEFILE: + print_notefile(stdout, todo->note, 1); + break; + case FS_PSIGN: + putchar('%'); + break; + case FS_EOF: + return; + break; + default: + putchar('?'); + break; + } + } else if (*p == '\\') + p += print_escape(p); + else + putchar(*p); + } } @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -48,6 +48,9 @@ int resize = 0; /* variable to tell if the terminal supports color */ unsigned colorize = 0; +/* Default background and foreground colors. */ +int foreground, background; + /* * To tell if curses interface was launched already or not (in that case * calcurse is running in command-line mode). @@ -55,11 +58,15 @@ unsigned colorize = 0; */ enum ui_mode ui_mode = UI_CMDLINE; +/* Don't save anything if this is set. */ +int read_only = 0; + /* * variables to store calendar names */ int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -char *monthnames[12] = { + +const char *monthnames[12] = { N_("January"), N_("February"), N_("March"), @@ -74,7 +81,7 @@ char *monthnames[12] = { N_("December") }; -char *daynames[8] = { +const char *daynames[8] = { N_("Sun"), N_("Mon"), N_("Tue"), @@ -99,6 +106,9 @@ char path_cpid[] = ""; char path_dpid[] = ""; char path_dmon_log[] = ""; +/* Variable to store global configuration. */ +struct conf conf; + /* Variable to handle pads. */ struct pad apad; @@ -111,45 +121,45 @@ struct dmon_conf dmon; /* * Variables init */ -void -vars_init (struct conf *conf) +void vars_init(void) { - char *ed, *pg; + const char *ed, *pg; /* Variables for user configuration */ - conf->confirm_quit = 1; - conf->confirm_delete = 1; - conf->auto_save = 1; - conf->periodic_save = 0; - conf->skip_system_dialogs = 0; - conf->skip_progress_bar = 0; - (void)strncpy (conf->output_datefmt, "%D", 3); - conf->input_datefmt = 1; + conf.confirm_quit = 1; + conf.confirm_delete = 1; + conf.auto_save = 1; + conf.auto_gc = 0; + conf.periodic_save = 0; + conf.system_dialogs = 1; + conf.progress_bar = 1; + strncpy(conf.output_datefmt, "%D", 3); + conf.input_datefmt = 1; /* Default external editor and pager */ - ed = getenv ("VISUAL"); + ed = getenv("VISUAL"); if (ed == NULL || ed[0] == '\0') - ed = getenv ("EDITOR"); + ed = getenv("EDITOR"); if (ed == NULL || ed[0] == '\0') ed = DEFAULT_EDITOR; - conf->editor = ed; + conf.editor = ed; - pg = getenv ("PAGER"); + pg = getenv("PAGER"); if (pg == NULL || pg[0] == '\0') pg = DEFAULT_PAGER; - conf->pager = pg; + conf.pager = pg; - wins_set_layout (1); + wins_set_layout(1); - calendar_set_first_day_of_week (MONDAY); + calendar_set_first_day_of_week(MONDAY); /* Pad structure to scroll text inside the appointment panel */ apad.length = 1; apad.first_onscreen = 0; /* Attribute definitions for color and non-color terminals */ - custom_init_attr (); + custom_init_attr(); /* Start at the current date */ - calendar_init_slctd_day (); + calendar_init_slctd_day(); } @@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * 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 @@ -44,7 +44,7 @@ struct window win[NBWINS]; /* User-configurable side bar width. */ -static unsigned sbarwidth; +static unsigned sbarwidth_perc; static enum win slctd_win; static int layout; @@ -63,93 +63,85 @@ static int layout; */ static pthread_mutex_t screen_mutex = PTHREAD_MUTEX_INITIALIZER; -static unsigned -screen_acquire (void) +static unsigned screen_acquire(void) { - if (pthread_mutex_lock (&screen_mutex) != 0) + if (pthread_mutex_lock(&screen_mutex) != 0) return 0; else return 1; } -static void -screen_release (void) +static void screen_release(void) { - (void)pthread_mutex_unlock (&screen_mutex); + pthread_mutex_unlock(&screen_mutex); } -int -wins_refresh (void) +int wins_refresh(void) { int rc; - if (!screen_acquire ()) + if (!screen_acquire()) return ERR; - rc = refresh (); - screen_release (); + rc = refresh(); + screen_release(); return rc; } -int -wins_wrefresh (WINDOW *win) +int wins_wrefresh(WINDOW * win) { int rc; - if (!win || !screen_acquire ()) + if (!win || !screen_acquire()) return ERR; - rc = wrefresh (win); - screen_release (); + rc = wrefresh(win); + screen_release(); return rc; } -int -wins_doupdate (void) +int wins_doupdate(void) { int rc; - if (!screen_acquire ()) + if (!screen_acquire()) return ERR; - rc = doupdate (); - screen_release (); + rc = doupdate(); + screen_release(); return rc; } /* Get the current layout. */ -int -wins_layout (void) +int wins_layout(void) { return layout; } /* Set the current layout. */ -void -wins_set_layout (int nb) +void wins_set_layout(int nb) { layout = nb; } /* Get the current side bar width. */ -unsigned -wins_sbar_width (void) +unsigned wins_sbar_width(void) { - return sbarwidth ? sbarwidth : SBARMINWIDTH; + if (sbarwidth_perc > SBARMAXWIDTHPERC) + return col * SBARMAXWIDTHPERC / 100; + else { + unsigned sbarwidth = (unsigned)(col * sbarwidth_perc / 100); + return (sbarwidth < SBARMINWIDTH) ? SBARMINWIDTH : sbarwidth; + } } /* * Return the side bar width in percentage of the total number of columns * available in calcurse's screen. */ -unsigned -wins_sbar_wperc (void) +unsigned wins_sbar_wperc(void) { - unsigned perc; - - perc = col ? (unsigned)(100 * sbarwidth / col + 1): 0; - - return perc > SBARMAXWIDTHPERC ? SBARMAXWIDTHPERC : perc; + return sbarwidth_perc > SBARMAXWIDTHPERC ? SBARMAXWIDTHPERC : sbarwidth_perc; } /* @@ -158,62 +150,44 @@ wins_sbar_wperc (void) * The side bar could not have a width representing more than 50% of the screen, * and could not be less than SBARMINWIDTH characters. */ -void -wins_set_sbar_width (unsigned perc) +void wins_set_sbar_width(unsigned perc) { - if (perc > SBARMAXWIDTHPERC) - sbarwidth = col * SBARMAXWIDTHPERC / 100; - else if (perc <= 0) - sbarwidth = SBARMINWIDTH; - else - { - sbarwidth = (unsigned)(col * perc / 100); - if (sbarwidth < SBARMINWIDTH) - sbarwidth = SBARMINWIDTH; - } + sbarwidth_perc = perc; } /* Change the width of the side bar within acceptable boundaries. */ -void -wins_sbar_winc (void) +void wins_sbar_winc(void) { - if (sbarwidth < SBARMINWIDTH) - sbarwidth = SBARMINWIDTH + 1; - else if (sbarwidth < SBARMAXWIDTHPERC * col / 100) - sbarwidth++; + if (sbarwidth_perc < SBARMAXWIDTHPERC) + sbarwidth_perc++; } -void -wins_sbar_wdec (void) +void wins_sbar_wdec(void) { - if (sbarwidth > SBARMINWIDTH) - sbarwidth--; + if (sbarwidth_perc > 0) + sbarwidth_perc--; } /* Initialize the selected window in calcurse's interface. */ -void -wins_slctd_init (void) +void wins_slctd_init(void) { - wins_slctd_set (CAL); + wins_slctd_set(CAL); } /* Returns an enum which corresponds to the window which is selected. */ -enum win -wins_slctd (void) +enum win wins_slctd(void) { - return (slctd_win); + return slctd_win; } /* Sets the selected window. */ -void -wins_slctd_set (enum win window) +void wins_slctd_set(enum win window) { slctd_win = window; } /* TAB key was hit in the interface, need to select next window. */ -void -wins_slctd_next (void) +void wins_slctd_next(void) { if (slctd_win == TOD) slctd_win = CAL; @@ -221,39 +195,32 @@ wins_slctd_next (void) slctd_win++; } -static void -wins_init_panels (void) +static void wins_init_panels(void) { - char label[BUFSIZ]; - - win[CAL].p = newwin (CALHEIGHT, wins_sbar_width (), win[CAL].y, win[CAL].x); - (void)snprintf (label, BUFSIZ, _("Calendar")); - wins_show (win[CAL].p, label); + win[CAL].p = newwin(CALHEIGHT, 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); - (void)snprintf (label, BUFSIZ, _("Appointments")); - wins_show (win[APP].p, label); + win[APP].p = newwin(win[APP].h, win[APP].w, win[APP].y, win[APP].x); + wins_show(win[APP].p, _("Appointments")); apad.width = win[APP].w - 3; - apad.ptrwin = newpad (apad.length, apad.width); + apad.ptrwin = newpad(apad.length, apad.width); - win[TOD].p = newwin (win[TOD].h, win[TOD].w, win[TOD].y, win[TOD].x); - (void)snprintf (label, BUFSIZ, _("ToDo")); - wins_show (win[TOD].p, label); + win[TOD].p = newwin(win[TOD].h, win[TOD].w, win[TOD].y, win[TOD].x); + wins_show(win[TOD].p, _("ToDo")); /* Enable function keys (i.e. arrow keys) in those windows */ - keypad (win[CAL].p, TRUE); - keypad (win[APP].p, TRUE); - keypad (win[TOD].p, TRUE); + keypad(win[CAL].p, TRUE); + keypad(win[APP].p, TRUE); + keypad(win[TOD].p, TRUE); } /* Create all the windows. */ -void -wins_init (void) +void wins_init(void) { - wins_init_panels (); - win[STA].p = newwin (win[STA].h, win[STA].w, win[STA].y, win[STA].x); + wins_init_panels(); + win[STA].p = newwin(win[STA].h, win[STA].w, win[STA].y, win[STA].x); - keypad (win[STA].p, TRUE); + keypad(win[STA].p, TRUE); /* Notify that the curses mode is now launched. */ ui_mode = UI_CURSES; @@ -263,116 +230,105 @@ wins_init (void) * Create a new window and its associated pad, which is used to make the * scrolling faster. */ -void -wins_scrollwin_init (struct scrollwin *sw) +void wins_scrollwin_init(struct scrollwin *sw) { - EXIT_IF (sw == NULL, "null pointer"); - sw->win.p = newwin (sw->win.h, sw->win.w, sw->win.y, sw->win.x); - sw->pad.p = newpad (sw->pad.h, sw->pad.w); + EXIT_IF(sw == NULL, "null pointer"); + sw->win.p = newwin(sw->win.h, sw->win.w, sw->win.y, sw->win.x); + sw->pad.p = newpad(sw->pad.h, sw->pad.w); sw->first_visible_line = 0; sw->total_lines = 0; } /* Free an already created scrollwin. */ -void -wins_scrollwin_delete (struct scrollwin *sw) +void wins_scrollwin_delete(struct scrollwin *sw) { - EXIT_IF (sw == NULL, "null pointer"); + EXIT_IF(sw == NULL, "null pointer"); delwin(sw->win.p); delwin(sw->pad.p); } /* Display a scrolling window. */ -void -wins_scrollwin_display (struct scrollwin *sw) +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_top = highend + 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_top = highend + sw->pad.y + 1; - if ((sbar_top + sbar_length) > sw->win.h - 1) - sbar_length = sw->win.h - sbar_top; - draw_scrollbar (sw->win.p, sbar_top, sw->win.w + sw->win.x - 2, - sbar_length, sw->pad.y + 1, sw->win.h - 1, 1); - } - wmove (win[STA].p, 0, 0); - wnoutrefresh (sw->win.p); - pnoutrefresh (sw->pad.p, sw->first_visible_line, 0, sw->pad.y, sw->pad.x, - sw->win.h - sw->pad.y + 1, sw->win.w - sw->win.x); - wins_doupdate (); + if ((sbar_top + sbar_length) > sw->win.h - 1) + sbar_length = sw->win.h - sbar_top; + draw_scrollbar(sw->win.p, sbar_top, sw->win.w + sw->win.x - 2, + sbar_length, sw->pad.y + 1, sw->win.h - 1, 1); + } + wmove(win[STA].p, 0, 0); + wnoutrefresh(sw->win.p); + pnoutrefresh(sw->pad.p, sw->first_visible_line, 0, sw->pad.y, sw->pad.x, + sw->win.h - sw->pad.y + 1, sw->win.w - sw->win.x); + wins_doupdate(); } -void -wins_scrollwin_up (struct scrollwin *sw, int amount) +void wins_scrollwin_up(struct scrollwin *sw, int amount) { if (sw->first_visible_line > 0) sw->first_visible_line -= amount; } -void -wins_scrollwin_down (struct scrollwin *sw, int amount) +void wins_scrollwin_down(struct scrollwin *sw, int amount) { - if (sw->total_lines - > (sw->first_visible_line + sw->win.h - sw->pad.y - 1)) + if (sw->total_lines > (sw->first_visible_line + sw->win.h - sw->pad.y - 1)) sw->first_visible_line += amount; } -void -wins_reinit_panels (void) +void wins_reinit_panels(void) { - delwin (win[CAL].p); - delwin (win[APP].p); - delwin (apad.ptrwin); - delwin (win[TOD].p); - wins_get_config (); - wins_init_panels (); + delwin(win[CAL].p); + delwin(win[APP].p); + delwin(apad.ptrwin); + delwin(win[TOD].p); + wins_get_config(); + wins_init_panels(); } /* * Delete the existing windows and recreate them with their new * size and placement. */ -void -wins_reinit (void) +void wins_reinit(void) { - delwin (win[CAL].p); - delwin (win[APP].p); - delwin (apad.ptrwin); - delwin (win[TOD].p); - delwin (win[STA].p); - wins_get_config (); - wins_init (); - if (notify_bar ()) - notify_reinit_bar (); + delwin(win[CAL].p); + delwin(win[APP].p); + delwin(apad.ptrwin); + delwin(win[TOD].p); + delwin(win[STA].p); + wins_get_config(); + wins_init(); + if (notify_bar()) + notify_reinit_bar(); } /* Show the window with a border and a label. */ -void -wins_show (WINDOW *win, char *label) +void wins_show(WINDOW * win, const char *label) { - int width = getmaxx (win); + 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); + 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); + print_in_middle(win, 1, 0, width, label); } /* * Get the screen size and recalculate the windows configurations. */ -void -wins_get_config (void) +void wins_get_config(void) { /* Get the screen configuration */ - getmaxyx (stdscr, row, col); + getmaxyx(stdscr, row, col); /* fixed values for status, notification bars and calendar */ win[STA].h = STATUSHEIGHT; @@ -380,267 +336,243 @@ wins_get_config (void) win[STA].y = row - win[STA].h; win[STA].x = 0; - if (notify_bar ()) - { - win[NOT].h = 1; - win[NOT].w = col; - win[NOT].y = win[STA].y - 1; - win[NOT].x = 0; - } - else - { - win[NOT].h = 0; - win[NOT].w = 0; - win[NOT].y = 0; - win[NOT].x = 0; - } - - win[CAL].w = wins_sbar_width (); + if (notify_bar()) { + win[NOT].h = 1; + win[NOT].w = col; + win[NOT].y = win[STA].y - 1; + win[NOT].x = 0; + } else { + win[NOT].h = 0; + win[NOT].w = 0; + win[NOT].y = 0; + win[NOT].x = 0; + } + + win[CAL].w = wins_sbar_width(); win[CAL].h = CALHEIGHT; - 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; - 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; - win[APP].h = row - (win[CAL].h + win[STA].h + win[NOT].h); - } + 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; + 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; + win[APP].h = row - (win[CAL].h + win[STA].h + win[NOT].h); + } /* 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; - } + 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; + } } /* draw panel border in color */ -static void -border_color (WINDOW *window) +static void border_color(WINDOW * window) { int color_attr = A_BOLD; int no_color_attr = A_BOLD; - if (colorize) - { - wattron (window, color_attr | COLOR_PAIR (COLR_CUSTOM)); - box (window, 0, 0); - } - else - { - wattron (window, no_color_attr); - box (window, 0, 0); - } - if (colorize) - { - wattroff (window, color_attr | COLOR_PAIR (COLR_CUSTOM)); - } - else - { - wattroff (window, no_color_attr); - } - wnoutrefresh (window); + if (colorize) { + wattron(window, color_attr | COLOR_PAIR(COLR_CUSTOM)); + box(window, 0, 0); + } else { + wattron(window, no_color_attr); + box(window, 0, 0); + } + if (colorize) { + wattroff(window, color_attr | COLOR_PAIR(COLR_CUSTOM)); + } else { + wattroff(window, no_color_attr); + } + wnoutrefresh(window); } /* draw panel border without any color */ -static void -border_nocolor (WINDOW *window) +static void border_nocolor(WINDOW * window) { int color_attr = A_BOLD; int no_color_attr = A_DIM; - if (colorize) - { - wattron (window, color_attr | COLOR_PAIR (COLR_DEFAULT)); - } - else - { - wattron (window, no_color_attr); - } - box (window, 0, 0); - if (colorize) - { - wattroff (window, color_attr | COLOR_PAIR (COLR_DEFAULT)); - } - else - { - wattroff (window, no_color_attr); - } - wnoutrefresh (window); -} - -void -wins_update_border (void) -{ - switch (slctd_win) - { - case CAL: - border_color (win[CAL].p); - border_nocolor (win[APP].p); - border_nocolor (win[TOD].p); - break; - case APP: - border_color (win[APP].p); - border_nocolor (win[CAL].p); - border_nocolor (win[TOD].p); - break; - case TOD: - border_color (win[TOD].p); - border_nocolor (win[APP].p); - border_nocolor (win[CAL].p); - break; - default: - EXIT (_("no window selected")); - /* NOTREACHED */ - } -} - -void -wins_update_panels (void) -{ - apoint_update_panel (slctd_win); - todo_update_panel (slctd_win); - calendar_update_panel (&win[CAL]); + if (colorize) { + wattron(window, color_attr | COLOR_PAIR(COLR_DEFAULT)); + } else { + wattron(window, no_color_attr); + } + box(window, 0, 0); + if (colorize) { + wattroff(window, color_attr | COLOR_PAIR(COLR_DEFAULT)); + } else { + wattroff(window, no_color_attr); + } + wnoutrefresh(window); +} + +void wins_update_border(int flags) +{ + if (flags & FLAG_CAL) { + if (slctd_win == CAL) + border_color(win[CAL].p); + else + border_nocolor(win[CAL].p); + } + if (flags & FLAG_APP) { + if (slctd_win == APP) + border_color(win[APP].p); + else + border_nocolor(win[APP].p); + } + if (flags & FLAG_TOD) { + if (slctd_win == TOD) + border_color(win[TOD].p); + else + border_nocolor(win[TOD].p); + } +} + +void wins_update_panels(int flags) +{ + if (flags & FLAG_APP) + apoint_update_panel(slctd_win); + if (flags & FLAG_TOD) + todo_update_panel(slctd_win); + if (flags & FLAG_CAL) + calendar_update_panel(&win[CAL]); } /* * Update all of the three windows and put a border around the * selected window. */ -void -wins_update (void) +void wins_update(int flags) { - wins_update_border (); - wins_update_panels (); - wins_status_bar (); - if (notify_bar ()) - notify_update_bar (); - wmove (win[STA].p, 0, 0); - wins_doupdate (); + wins_update_border(flags); + wins_update_panels(flags); + if (flags & FLAG_STA) + wins_status_bar(); + if ((flags & FLAG_NOT) && notify_bar()) + notify_update_bar(); + wmove(win[STA].p, 0, 0); + wins_doupdate(); } /* Reset the screen, needed when resizing terminal for example. */ -void -wins_reset (void) +void wins_reset(void) { - endwin (); - wins_refresh (); - curs_set (0); - wins_reinit (); - wins_update (); + endwin(); + wins_refresh(); + curs_set(0); + wins_reinit(); + wins_update(FLAG_ALL); +} + +/* Prepare windows for the execution of an external command. */ +void wins_prepare_external(void) +{ + if (notify_bar()) + notify_stop_main_thread(); + def_prog_mode(); + ui_mode = UI_CMDLINE; + clear(); + wins_refresh(); + endwin(); +} + +/* Restore windows when returning from an external command. */ +void wins_unprepare_external(void) +{ + reset_prog_mode(); + clearok(curscr, TRUE); + curs_set(0); + ui_mode = UI_CURSES; + wins_refresh(); + if (notify_bar()) + notify_start_main_thread(); } /* * While inside interactive mode, launch the external command cmd on the given * file. */ -void -wins_launch_external (const char *file, const char *cmd) -{ - char *p; - int len; - - /* Beware of space between cmd and file. */ - len = strlen (file) + strlen (cmd) + 2; - - p = (char *) mem_calloc (len, sizeof (char)); - if (snprintf (p, len, "%s %s", cmd, file) == -1) - { - mem_free (p); - return; - } - if (notify_bar ()) - notify_stop_main_thread (); - def_prog_mode (); - endwin (); - ui_mode = UI_CMDLINE; - clear (); - wins_refresh (); - (void)system (p); - reset_prog_mode (); - clearok (curscr, TRUE); - curs_set (0); - ui_mode = UI_CURSES; - wins_refresh (); - if (notify_bar ()) - notify_start_main_thread (); - mem_free (p); +void wins_launch_external(const char *file, const char *cmd) +{ + const char *arg[] = { cmd, file, NULL }; + int pid; + + wins_prepare_external(); + if ((pid = shell_exec(NULL, NULL, *arg, arg))) + child_wait(NULL, NULL, pid); + wins_unprepare_external(); } -#define NB_CAL_CMDS 27 /* number of commands while in cal view */ -#define NB_APP_CMDS 31 /* same thing while in appointment view */ -#define NB_TOD_CMDS 30 /* same thing while in todo view */ -#define TOTAL_CMDS NB_CAL_CMDS + NB_APP_CMDS + NB_TOD_CMDS -#define CMDS_PER_LINE 6 /* max number of commands per line */ +#define NB_CAL_CMDS 27 /* number of commands while in cal view */ +#define NB_APP_CMDS 32 /* same thing while in appointment view */ +#define NB_TOD_CMDS 31 /* same thing while in todo view */ static unsigned status_page; @@ -650,114 +582,124 @@ static unsigned status_page; * table, and update the NB_CAL_CMDS, NB_APP_CMDS or NB_TOD_CMDS defines, * depending on which panel the added keybind is assigned to. */ -void -wins_status_bar (void) -{ -#define NB_PANELS 3 /* 3 panels: CALENDAR, APPOINTMENT, TODO */ - enum win which_pan; - int start, end; - const int pos[NB_PANELS + 1] = - { 0, NB_CAL_CMDS, NB_CAL_CMDS + NB_APP_CMDS, TOTAL_CMDS }; - - 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 paste = {_("Paste"), KEY_GENERIC_PASTE}; - struct binding chgvu = {_("Chg Win"), KEY_GENERIC_CHANGE_VIEW}; - struct binding import = {_("Import"), KEY_GENERIC_IMPORT}; - struct binding export = {_("Export"), KEY_GENERIC_EXPORT}; - struct binding togo = {_("Go to"), KEY_GENERIC_GOTO}; - struct binding othr = {_("OtherCmd"), KEY_GENERIC_OTHER_CMD}; - struct binding conf = {_("Config"), KEY_GENERIC_CONFIG_MENU}; - struct binding draw = {_("Redraw"), KEY_GENERIC_REDRAW}; - struct binding appt = {_("Add Appt"), KEY_GENERIC_ADD_APPT}; - struct binding todo = {_("Add Todo"), KEY_GENERIC_ADD_TODO}; - struct binding gnday = {_("+1 Day"), KEY_GENERIC_NEXT_DAY}; - struct binding gpday = {_("-1 Day"), KEY_GENERIC_PREV_DAY}; - struct binding gnweek = {_("+1 Week"), KEY_GENERIC_NEXT_WEEK}; - struct binding gpweek = {_("-1 Week"), KEY_GENERIC_PREV_WEEK}; - struct binding today = {_("Today"), KEY_GENERIC_GOTO_TODAY}; - struct binding nview = {_("Nxt View"), KEY_GENERIC_SCROLL_DOWN}; - struct binding pview = {_("Prv View"), KEY_GENERIC_SCROLL_UP}; - struct binding up = {_("Up"), KEY_MOVE_UP}; - struct binding down = {_("Down"), KEY_MOVE_DOWN}; - struct binding left = {_("Left"), KEY_MOVE_LEFT}; - struct binding right = {_("Right"), KEY_MOVE_RIGHT}; - struct binding weekb = {_("beg Week"), KEY_START_OF_WEEK}; - struct binding weeke = {_("end Week"), KEY_END_OF_WEEK}; - struct binding add = {_("Add Item"), KEY_ADD_ITEM}; - struct binding del = {_("Del Item"), KEY_DEL_ITEM}; - struct binding edit = {_("Edit Itm"), KEY_EDIT_ITEM}; - struct binding view = {_("View"), KEY_VIEW_ITEM}; - struct binding flag = {_("Flag Itm"), KEY_FLAG_ITEM}; - struct binding rept = {_("Repeat"), KEY_REPEAT_ITEM}; - struct binding enote = {_("EditNote"), KEY_EDIT_NOTE}; - struct binding vnote = {_("ViewNote"), KEY_VIEW_NOTE}; - struct binding rprio = {_("Prio.+"), KEY_RAISE_PRIORITY}; - struct binding lprio = {_("Prio.-"), KEY_LOWER_PRIORITY}; - - struct binding *binding[TOTAL_CMDS] = { - /* calendar keys */ +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 paste = { _("Paste"), KEY_GENERIC_PASTE }; + struct binding chgvu = { _("Chg Win"), KEY_GENERIC_CHANGE_VIEW }; + struct binding import = { _("Import"), KEY_GENERIC_IMPORT }; + struct binding export = { _("Export"), KEY_GENERIC_EXPORT }; + struct binding togo = { _("Go to"), KEY_GENERIC_GOTO }; + struct binding conf = { _("Config"), KEY_GENERIC_CONFIG_MENU }; + struct binding draw = { _("Redraw"), KEY_GENERIC_REDRAW }; + struct binding appt = { _("Add Appt"), KEY_GENERIC_ADD_APPT }; + struct binding todo = { _("Add Todo"), KEY_GENERIC_ADD_TODO }; + struct binding gnday = { _("+1 Day"), KEY_GENERIC_NEXT_DAY }; + struct binding gpday = { _("-1 Day"), KEY_GENERIC_PREV_DAY }; + struct binding gnweek = { _("+1 Week"), KEY_GENERIC_NEXT_WEEK }; + struct binding gpweek = { _("-1 Week"), KEY_GENERIC_PREV_WEEK }; + struct binding today = { _("Today"), KEY_GENERIC_GOTO_TODAY }; + struct binding nview = { _("Nxt View"), KEY_GENERIC_SCROLL_DOWN }; + struct binding pview = { _("Prv View"), KEY_GENERIC_SCROLL_UP }; + struct binding up = { _("Up"), KEY_MOVE_UP }; + struct binding down = { _("Down"), KEY_MOVE_DOWN }; + struct binding left = { _("Left"), KEY_MOVE_LEFT }; + struct binding right = { _("Right"), KEY_MOVE_RIGHT }; + struct binding weekb = { _("beg Week"), KEY_START_OF_WEEK }; + struct binding weeke = { _("end Week"), KEY_END_OF_WEEK }; + struct binding add = { _("Add Item"), KEY_ADD_ITEM }; + struct binding del = { _("Del Item"), KEY_DEL_ITEM }; + struct binding edit = { _("Edit Itm"), KEY_EDIT_ITEM }; + struct binding view = { _("View"), KEY_VIEW_ITEM }; + struct binding pipe = { _("Pipe"), KEY_PIPE_ITEM }; + struct binding flag = { _("Flag Itm"), KEY_FLAG_ITEM }; + struct binding rept = { _("Repeat"), KEY_REPEAT_ITEM }; + struct binding enote = { _("EditNote"), KEY_EDIT_NOTE }; + struct binding vnote = { _("ViewNote"), KEY_VIEW_NOTE }; + struct binding rprio = { _("Prio.+"), KEY_RAISE_PRIORITY }; + struct binding lprio = { _("Prio.-"), KEY_LOWER_PRIORITY }; + struct binding othr = { _("OtherCmd"), KEY_GENERIC_OTHER_CMD }; + + struct binding *bindings_cal[] = { &help, &quit, &save, &chgvu, &nview, &pview, &up, &down, &left, &right, - &togo, &othr, &import, &export, &weekb, &weeke, &appt, &todo, - &gnday, &gpday, &gnweek, &gpweek, &draw, &othr, &today, &conf, &othr, - /* appointment keys */ + &togo, &import, &export, &weekb, &weeke, &appt, &todo, &gnday, &gpday, + &gnweek, &gpweek, &draw, &today, &conf + }; + + struct binding *bindings_apoint[] = { &help, &quit, &save, &chgvu, &import, &export, &add, &del, &edit, &view, - &draw, &othr, &rept, &flag, &enote, &vnote, &up, &down, &gnday, &gpday, - &gnweek, &gpweek, &togo, &othr, &today, &conf, &appt, &todo, &cut, &paste, - &othr, - /* todo keys */ + &pipe, &draw, &rept, &flag, &enote, &vnote, &up, &down, &gnday, &gpday, + &gnweek, &gpweek, &togo, &today, &conf, &appt, &todo, &cut, &paste + }; + + struct binding *bindings_todo[] = { &help, &quit, &save, &chgvu, &import, &export, &add, &del, &edit, &view, - &flag, &othr, &rprio, &lprio, &enote, &vnote, &up, &down, &gnday, &gpday, - &gnweek, &gpweek, &togo, &othr, &today, &conf, &appt, &todo, &draw, &othr + &pipe, &flag, &rprio, &lprio, &enote, &vnote, &up, &down, &gnday, &gpday, + &gnweek, &gpweek, &togo, &today, &conf, &appt, &todo, &draw }; - /* Drawing the keybinding with attribute and label without. */ - which_pan = wins_slctd (); - start = pos[which_pan] + 2 * KEYS_CMDS_PER_LINE * (status_page - 1); - end = MIN (start + 2 * KEYS_CMDS_PER_LINE, pos[which_pan + 1]); - keys_display_bindings_bar (win[STA].p, binding, start, end); + enum win active_panel = wins_slctd(); + + struct binding **bindings; + int bindings_size; + + switch (active_panel) { + case CAL: + bindings = bindings_cal; + bindings_size = sizeof(bindings_cal) / sizeof(bindings_cal[0]); + break; + case APP: + bindings = bindings_apoint; + bindings_size = sizeof(bindings_apoint) / sizeof(bindings_apoint[0]); + break; + case TOD: + bindings = bindings_todo; + bindings_size = sizeof(bindings_todo) / sizeof(bindings_todo[0]); + break; + default: + EXIT(_("unknown panel")); + /* NOTREACHED */ + } + + keys_display_bindings_bar(win[STA].p, bindings, bindings_size, + (KEYS_CMDS_PER_LINE * 2 - 1) * (status_page - 1), + KEYS_CMDS_PER_LINE * 2, &othr); } /* Erase status bar. */ -void -wins_erase_status_bar (void) +void wins_erase_status_bar(void) { - erase_window_part (win[STA].p, 0, 0, col, STATUSHEIGHT); + erase_window_part(win[STA].p, 0, 0, col, STATUSHEIGHT); } /* Update the status bar page number to display other commands. */ -void -wins_other_status_page (int panel) +void wins_other_status_page(int panel) { int nb_item, max_page; - switch (panel) - { - case CAL: - nb_item = NB_CAL_CMDS; - break; - case APP: - nb_item = NB_APP_CMDS; - break; - case TOD: - nb_item = NB_TOD_CMDS; - break; - default: - EXIT (_("unknown panel")); - /* NOTREACHED */ - } - max_page = ceil (nb_item / (2 * CMDS_PER_LINE + 1)) + 1; - if (status_page < max_page) - status_page++; - else - status_page = 1; + switch (panel) { + case CAL: + nb_item = NB_CAL_CMDS; + break; + case APP: + nb_item = NB_APP_CMDS; + break; + case TOD: + nb_item = NB_TOD_CMDS; + break; + default: + EXIT(_("unknown panel")); + /* NOTREACHED */ + } + max_page = nb_item / (KEYS_CMDS_PER_LINE * 2 - 1) + 1; + status_page = (status_page % max_page) + 1; } /* Reset the status bar page. */ -void -wins_reset_status_page (void) +void wins_reset_status_page(void) { status_page = 1; } @@ -765,5 +707,3 @@ wins_reset_status_page (void) #undef NB_CAL_CMDS #undef NB_APP_CMDS #undef NB_TOD_CMDS -#undef TOTAL_CMDS -#undef CMDS_PER_LINE diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..85c8a1d --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,31 @@ +AUTOMAKE_OPTIONS = foreign + +TESTS = \ + true-001.sh \ + run-test-001.sh \ + run-test-002.sh \ + todo-001.sh \ + todo-002.sh \ + todo-003.sh \ + day-001.sh \ + day-002.sh \ + day-003.sh \ + range-001.sh \ + range-002.sh \ + range-003.sh \ + appointment-001.sh \ + next-001.sh \ + search-001.sh + +TESTS_ENVIRONMENT = \ + CALCURSE='$(top_builddir)/src/calcurse' \ + DATA_DIR='$(top_srcdir)/test/data/' + +AM_CFLAGS = -std=c99 -pedantic -D_POSIX_C_SOURCE=200809L + +check_PROGRAMS = run-test +check_SCRIPTS = $(TESTS) + +run_test_SOURCES = run-test.c + +EXTRA_DIST = $(TESTS) data/apts data/conf data/todo diff --git a/test/README b/test/README new file mode 100644 index 0000000..f0fd06a --- /dev/null +++ b/test/README @@ -0,0 +1,121 @@ +calcurse Test Suite +=================== + +This directory holds of a couple of test cases and some helpers to simplify the +task of creating new tests. Test cases are intended to test a specified set of +behaviors and to avoid reintroduction of bugs that have already been fixed. The +idea is that a new test should be added for each bug report that is received +and for each bug that is fixed in the development branch. + +Running tests +------------- + +The easiest way to run tests is running `make check`. This will prepare and +compile all needed components and start all test cases. A summary is displayed +when all tests are finished. + +You can also run tests manually. Test cases are usually shell scripts or +binaries. To run an individual test, just invoke the corresponding executable. +Note that some tests require the `CALCURSE` and `DATA_DIR` environment +variables to be set, where `CALCURSE` should point to a valid calcurse binary +and `DATA_DIR` should point to a valid data directory. We usually use the data +directory `data/`, which is contained in the `test/` directory, for test cases: + + $ CALCURSE=../src/calcurse DATA_DIR=data/ ./next-001.sh + Running ./next-001.sh... ok + +Passing another data directory might cause some failures since many tests are +adapted for the `test/` directory provided by the test suite: + + $ CALCURSE=../src/calcurse DATA_DIR="$HOME/.calcurse/" ./next-001.sh + Running ./next-001.sh... FAIL + +Writing tests +------------- + +Writing test cases is as simple as creating a new shell script and adding some +test code. Success and failure are reported by setting the exit status. Setting +the exit status to `0` indicates success, a non-zero value indicates failure +(which reflects the usual exit code semantics of POSIX systems). + +To enable a test, just add it to the `TESTS` variable in `test/Makefile.am`. If +your test case is written in a non-interpretable language, you may need to add +some compilation directives as well. Please note that we only accept +POSIX-compatible shell scripts and C in mainline, so please avoid using other +languages if you plan to get your test case integrated upstream. + +If your test case invokes the calcurse binary, please continue reading the +following sections, also. + +The `run-test` helper +--------------------- + +The `run-test` helper is a simple C program that makes writing script-based +test cases much easier. Tests for the calcurse command line interface usually +invoke the calcurse binary with some special command line options and compare +the output with a hardcoded set of expected results. Unfortunately, comparing +the output of two commands is not exactly easy in POSIX shell: this is where +the `run-test` helper comes in handy. + +If you run the `run-test` helper, you can pass one or more executable files as +parameters. The helper then invokes each of the specified scripts twice: Once +passing `actual` as a command line parameter and once passing `expected`. It +then compares the outputs of both invocations and checks if they are equal or +not. If the `actual`/`expected` outputs differ for one of the programs passed +to `run-test`, if displays `FAIL` and exits with a non-zero exit status. It +returns success otherwise. + +Here is a simple example on how to use `run-test`: + + #!/bin/sh + + if [ "$1" = 'actual' ]; then + echo 'obrocodobro' | sed 's/o/a/g' + elif [ "$1" = 'expected' ]; then + echo 'abracadabra' + else + ./run-test "$0" + fi + +If the script is run without any parameters, it simply invokes `run-test`, +passing itself as a command line parameter (see the `else` branch). `run-test` +then reruns the script, passing `actual` as the first parameter. This starts +the actual test (see the `if` branch). It reruns the script a second time, +passing `expected` as the first parameter which results in the script printing +the expected result for this test (see the `elif` branch). Finally, `run-test` +compares both outputs, prints a message indicating whether they are equal and +sets the exit status accordingly. This exit status is then passed on to the +original instance of the test script and returned since `./run-test "$0"` is +the last command that is run if the script is invoked without any parameters. + +You should stick to this strategy whenever you want to check the output of a +non-interactive calcurse instance in a test. Check the following tests for some +more examples: + +* `todo-001.sh` +* `todo-002.sh` +* `todo-003.sh` + +Using libfaketime +----------------- + +Some tests might require faking current date and time. We currently use +libfaketime to achieve this. Check the following files for examples: + +* `appointment-001.sh` +* `next-001.sh` +* `range-001.sh` +* `range-002.sh` +* `range-003.sh` + +NOTE: Please do not forget to check for libfaketime presence at the beginning +of your test. Otherwise, your test is likely to fail on systems that are not +supported by libfaketime. + +Additional notes +---------------- + +Most tests, that invoke the calcurse binary, pass the `--read-only` parameter +to make sure the data directory is not modified by calcurse, preventing +unexpected side effects. Please follow this guideline if you plan to submit +your patch upstream. diff --git a/test/appointment-001.sh b/test/appointment-001.sh new file mode 100755 index 0000000..27813b3 --- /dev/null +++ b/test/appointment-001.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +if [ ! -x "$(command -v faketime)" ]; then + echo "libfaketime not found - skipping $0..." + exit 1 +fi + +if [ "$1" = 'actual' ]; then + faketime '2011-02-25 23:42' "$CALCURSE" --read-only -D "$DATA_DIR" -a +elif [ "$1" = 'expected' ]; then + cat <<EOD +02/25/11: + * Socket ghastlier + - ..:.. -> ..:.. + Covenants useful smoker's +EOD +else + ./run-test "$0" +fi diff --git a/test/data/apts b/test/data/apts new file mode 100644 index 0000000..33de89b --- /dev/null +++ b/test/data/apts @@ -0,0 +1,660 @@ +12/27/1911 @ 01:18 -> 12/29/1911 @ 18:52 |Outsmarts Leoncavallo's daunting +02/10/1912 @ 20:36 -> 02/14/1912 @ 21:46 |Relieving uncleanliest footnoting unscrewed +04/28/1912 @ 02:54 -> 04/30/1912 @ 16:47 |Visit repel egotism antidepressant Idahos +07/10/1912 @ 17:47 -> 07/13/1912 @ 03:18 |Impersonating integer broils blame +09/27/1912 @ 16:07 -> 10/02/1912 @ 07:24 |Wedgwood's dilating +10/28/1913 @ 11:18 -> 11/01/1913 @ 17:07 |Deviation perspire +12/23/1913 @ 07:25 -> 12/23/1913 @ 17:46 |Nintendo stapler jellyfish vaporous +09/08/1914 @ 07:41 -> 09/11/1914 @ 18:15 |Panelling +03/22/1915 @ 07:21 -> 03/25/1915 @ 20:57 |Veritable intercom's +08/12/1915 @ 23:57 -> 08/16/1915 @ 23:02 |Meddlers presides prefabricates Disneyland's +08/27/1915 @ 07:34 -> 08/29/1915 @ 23:36 |EverReady's tramping patches napped +06/16/1916 @ 15:56 -> 06/19/1916 @ 15:05 |Rediscovery's Barnaby's lummox's shan't +06/19/1916 @ 15:35 -> 06/23/1916 @ 09:00 |Lu gastric Valenti bankruptcy's intents +10/01/1916 @ 08:13 -> 10/02/1916 @ 11:56 |Appropriately Potemkin's hassocks snappier Millay +12/12/1916 @ 12:04 -> 12/15/1916 @ 08:31 |Thefts infrastructure's chides +01/20/1917 @ 07:12 -> 01/20/1917 @ 12:19 |Outfit Hannah +07/22/1917 @ 04:28 -> 07/22/1917 @ 10:04 |Shallowness's tap's enjoining chewy obligation's +07/30/1917 @ 08:34 -> 08/04/1917 @ 11:53 |Stephan +03/25/1918 @ 11:14 -> 03/29/1918 @ 14:57 |Butterfat Cherry's aviators albs fattier +01/26/1919 @ 17:43 -> 01/26/1919 @ 23:18 |Creakiest cocking disporting polyhedron auditions +03/21/1919 @ 19:33 -> 03/23/1919 @ 03:37 |Stethoscopes Singer's vermouth pincers +04/01/1919 @ 23:51 -> 04/03/1919 @ 09:19 |Doughtiest +05/14/1919 @ 05:55 -> 05/16/1919 @ 22:47 |Aviation's O'Neill welding +06/21/1919 @ 01:48 -> 06/22/1919 @ 01:07 |Marquis grid sprinkling's +06/30/1919 @ 13:48 -> 07/03/1919 @ 06:08 |Barracudas +07/05/1919 @ 09:09 -> 07/10/1919 @ 10:56 |Lea's mullion remove connects collation's +09/07/1919 @ 20:52 -> 09/11/1919 @ 17:11 |Alps hotshot +01/21/1921 @ 19:57 -> 01/22/1921 @ 18:42 |Gunk +05/01/1921 @ 20:50 -> 05/01/1921 @ 20:57 |Citibank +06/19/1921 @ 08:01 -> 06/22/1921 @ 10:20 |Coziness sloshed retyping southwards intensified +08/02/1921 @ 16:46 -> 08/04/1921 @ 22:17 |Malawi's undefinable Copacabana hungered +08/04/1921 @ 00:58 -> 08/04/1921 @ 09:07 |Bagpipes dole shores +01/16/1922 @ 13:01 -> 01/17/1922 @ 14:32 |Gravies +06/23/1922 @ 13:56 -> 06/25/1922 @ 02:12 |Funnelling creation's regionalisms skivvied jaunted +07/08/1922 @ 17:13 -> 07/09/1922 @ 08:03 |Alleluia Freetown's +07/14/1922 @ 05:26 -> 07/19/1922 @ 11:28 |Pittsburgh's joined overbearing propellant's +03/07/1923 @ 17:37 -> 03/09/1923 @ 22:27 |Impulsion Sheffield's Swanson's +05/17/1923 @ 13:01 -> 05/19/1923 @ 04:23 |Disconnections +07/06/1923 @ 18:38 -> 07/09/1923 @ 13:26 |Sightseeing yarns +08/07/1923 @ 17:38 -> 08/11/1923 @ 03:34 |Tc's +12/20/1923 @ 11:05 -> 12/21/1923 @ 09:31 |Chanter snuffs Hymen +03/19/1924 @ 10:11 -> 03/20/1924 @ 04:34 |Powder imagines devastating +07/11/1924 @ 18:34 -> 07/13/1924 @ 09:32 |Manley's Telemann +01/24/1926 @ 09:39 -> 01/28/1926 @ 00:32 |Freebases improvidence maggot gestation's +06/30/1926 @ 17:36 -> 07/01/1926 @ 22:54 |Antibody poor Atlantes +07/24/1926 @ 13:52 -> 07/28/1926 @ 14:48 |Piety's +08/19/1926 @ 21:46 -> 08/21/1926 @ 00:07 |Incur hearties outlining sensationalists +09/15/1926 @ 09:13 -> 09/17/1926 @ 08:27 |Theocritus's +03/17/1927 @ 05:31 -> 03/17/1927 @ 17:55 |Closets scrape addictive consummations +05/27/1927 @ 12:40 -> 05/28/1927 @ 10:43 |Pharaoh Montoya bloods acclamation yesteryear's +06/05/1927 @ 15:47 -> 06/07/1927 @ 00:26 |Pawned subplot's Dzerzhinsky +11/18/1927 @ 13:33 -> 11/21/1927 @ 19:10 |Splurges +06/05/1928 @ 13:34 -> 06/06/1928 @ 17:32 |Auricle's precognition cytoplasm +07/02/1928 @ 05:14 -> 07/03/1928 @ 00:20 |Saboteurs crassest moderator's waif's fear's +10/24/1928 @ 02:11 -> 10/28/1928 @ 16:48 |Restorers indifferent Schwinger's Valentino's bowing +11/01/1928 @ 09:39 -> 11/05/1928 @ 02:18 |Dalmatians lionizing colonist hustle tawdrier +11/05/1928 @ 06:20 -> 11/08/1928 @ 17:22 |Boob's pied sorest +12/28/1928 @ 01:34 -> 12/28/1928 @ 01:43 |Intermezzo's cockerel +04/30/1929 @ 02:40 -> 05/02/1929 @ 13:42 |Unnecessarily imploring rebut Cuvier +08/29/1929 @ 08:55 -> 08/31/1929 @ 09:04 |Motherland distances cornbread reflect +09/16/1929 @ 11:58 -> 09/19/1929 @ 18:10 |Misstate ghoul +05/13/1930 @ 20:14 -> 05/15/1930 @ 01:57 |Groan's crabbed fifty's Mugabe +09/07/1930 @ 21:39 -> 09/11/1930 @ 14:25 |Surpasses received Kidd Midway consoled +11/06/1930 @ 05:01 -> 11/09/1930 @ 15:37 |Seafaring ravined petunia's babe's hose +06/24/1931 @ 20:40 -> 06/28/1931 @ 08:56 |Stiffening hodgepodges embarkation's +07/18/1931 @ 00:40 -> 07/21/1931 @ 21:13 |Colony explosions Gienah's +11/07/1931 @ 09:33 -> 11/10/1931 @ 07:30 |Intoxicant's Rex amphetamine's curacy's cardiologists +11/28/1931 @ 13:19 -> 11/29/1931 @ 10:56 |Sawdusting vicariously brunette's +03/22/1932 @ 07:58 -> 03/23/1932 @ 15:26 |Mailboxes pigment's jasmine +05/06/1932 @ 19:31 -> 05/08/1932 @ 15:08 |Felix's possibles debilitation's +12/07/1932 @ 14:30 -> 12/10/1932 @ 10:24 |Electioneering truces +03/18/1933 @ 16:50 -> 03/22/1933 @ 13:55 |Rotisseries powwowed abutment's crash evacuee's +08/24/1933 @ 09:24 -> 08/25/1933 @ 13:22 |Usage +12/28/1933 @ 10:48 -> 12/28/1933 @ 13:14 |Martial knitted woodenness's GE glassful's +01/12/1934 @ 00:25 -> 01/14/1934 @ 16:05 |Languors uncommonly magnetizing cataclysm +06/23/1934 @ 07:35 -> 06/28/1934 @ 00:23 |Pogromed +06/26/1934 @ 12:56 -> 07/01/1934 @ 00:06 |Outburst Delilah upbeat hooky ideologies +08/06/1934 @ 20:27 -> 08/09/1934 @ 08:18 |Effectuates kilogram region's Debby's +10/06/1934 @ 06:31 -> 10/11/1934 @ 01:13 |Leftest tire's propagation +10/21/1934 @ 18:18 -> 10/21/1934 @ 23:06 |Delta applause's backside allusion Lamb's +11/21/1934 @ 01:28 -> 11/25/1934 @ 12:28 |Milling discontinuances migration's introducing +11/29/1934 @ 21:28 -> 12/01/1934 @ 11:52 |Porpoise Angora's overwrite +04/19/1935 @ 01:32 -> 04/20/1935 @ 09:03 |Elbowing ricked +07/18/1935 @ 08:15 -> 07/22/1935 @ 18:48 |Anaerobic filmmakers +08/08/1935 @ 21:02 -> 08/10/1935 @ 02:18 |Isherwood's yearning's Modesto's forswearing +10/06/1935 @ 15:39 -> 10/11/1935 @ 07:45 |Mannerism's Koppel's Philippe's +11/06/1935 @ 22:58 -> 11/10/1935 @ 12:09 |Flog impacts +05/03/1936 @ 12:03 -> 05/07/1936 @ 06:07 |Pluralities Capitol +07/15/1936 @ 11:02 -> 07/17/1936 @ 19:10 |Sancta nones +08/05/1936 @ 14:13 -> 08/06/1936 @ 04:38 |Rustbelt slacking valedictorians +01/04/1937 @ 11:54 -> 01/04/1937 @ 14:31 |Gynecological Babur barking +05/20/1937 @ 04:24 -> 05/20/1937 @ 05:31 |Mayra's Muscovy grumble +02/08/1938 @ 12:02 -> 02/12/1938 @ 14:25 |Graveyards aha leftover's intrusted tobacco +02/15/1938 @ 11:18 -> 02/16/1938 @ 18:50 |Pt vulcanize Chayefsky Harlan cerebella +03/31/1938 @ 18:28 -> 04/01/1938 @ 12:12 |Musicologist's Lorie Indiana monograming +04/28/1938 @ 14:00 -> 05/01/1938 @ 17:35 |Stalingrad stagnating flame stacked +07/18/1938 @ 08:36 -> 07/21/1938 @ 10:02 |Vacuum lingering cantaloup +09/10/1938 @ 15:13 -> 09/11/1938 @ 13:50 |Unpleasant loudly ingredients owning +12/30/1938 @ 01:27 -> 12/30/1938 @ 18:30 |Exigent circumventing pundit Dietrich pertinents +11/27/1939 @ 22:21 -> 11/28/1939 @ 18:06 |Novice greasier +12/02/1939 @ 06:49 -> 12/06/1939 @ 05:46 |Lunchtimes compression Mazola's +02/27/1940 @ 09:29 -> 02/27/1940 @ 10:01 |Somnambulism Appomattox's ductile shades +01/21/1941 @ 00:48 -> 01/21/1941 @ 04:20 |Dysentery Oldfield phonograph lavendered +08/01/1941 @ 01:14 -> 08/02/1941 @ 09:11 |Garrotes species sandpapering +11/12/1941 @ 15:08 -> 11/13/1941 @ 05:37 |Gutierrez's discarding adjudicators astutest Alyce's +06/18/1942 @ 19:24 -> 06/19/1942 @ 09:01 |Lanyard +06/28/1942 @ 14:03 -> 06/30/1942 @ 02:29 |Panoramic murderesses +09/22/1942 @ 00:58 -> 09/26/1942 @ 21:44 |Malplaquet's Benelux pantsuit +12/06/1942 @ 09:46 -> 12/07/1942 @ 04:33 |Manuel glorified four +09/02/1943 @ 18:01 -> 09/03/1943 @ 10:39 |Decriminalized Bacon +12/15/1943 @ 15:40 -> 12/18/1943 @ 22:57 |Laundress Galibi's equine +01/30/1944 @ 01:51 -> 01/30/1944 @ 03:52 |Attenuates rarefying Pomeranian vivisection's laughably +03/18/1944 @ 17:11 -> 03/20/1944 @ 11:57 |Laundry's Cote's +06/28/1944 @ 23:38 -> 06/29/1944 @ 13:04 |Film's colonizer +04/20/1945 @ 12:03 -> 04/22/1945 @ 13:53 |Chandragupta shrimp payoff barometric zone's +06/08/1945 @ 11:23 -> 06/13/1945 @ 02:29 |Fling Jinnah +03/06/1946 @ 11:55 -> 03/11/1946 @ 04:52 |Drowning snailing drawbacks +03/17/1946 @ 12:16 -> 03/19/1946 @ 14:30 |Needles awnings roughhouses +03/19/1946 @ 21:06 -> 03/22/1946 @ 12:43 |Magpie's doohickey +06/22/1946 @ 19:16 -> 06/23/1946 @ 19:02 |Dobbin's spiked +10/23/1946 @ 15:44 -> 10/26/1946 @ 17:49 |Nauru Worcester +07/28/1947 @ 19:04 -> 08/03/1947 @ 02:17 |Manufacturer preterit's delectable fulcrum +03/25/1948 @ 11:07 -> 03/28/1948 @ 01:40 |Shaggiest Chan astrakhan marten +06/15/1948 @ 14:24 -> 06/17/1948 @ 19:03 |Cabrini directer pennies +05/25/1949 @ 11:16 -> 05/26/1949 @ 12:58 |Anybodies keystroke's +08/07/1949 @ 21:47 -> 08/08/1949 @ 13:21 |Ormolu Stephenson diatoms +10/23/1949 @ 19:18 -> 10/27/1949 @ 02:41 |Smouldering hales curios refinished dogmatic +10/28/1949 @ 03:45 -> 10/31/1949 @ 22:17 |Principals six Geller's +06/24/1950 @ 10:34 -> 06/28/1950 @ 12:35 |Disembowels +07/11/1950 @ 03:22 -> 07/12/1950 @ 17:20 |Coiffing Trent cosmologies penalizes minuteness's +07/20/1950 @ 14:25 -> 07/24/1950 @ 02:35 |Recreant eclipsed +10/13/1950 @ 21:53 -> 10/17/1950 @ 14:07 |Dredger +10/30/1950 @ 14:11 -> 10/31/1950 @ 15:34 |Unleashing tusk's incidences +12/10/1951 @ 05:28 -> 12/10/1951 @ 20:02 |Linemen +09/03/1952 @ 05:06 -> 09/03/1952 @ 11:52 |Simmons +11/05/1952 @ 15:24 -> 11/06/1952 @ 21:10 |Sheers quiche mixture's proprietorship's cone +12/04/1952 @ 02:54 -> 12/05/1952 @ 18:40 |Unreal collaboration jabots pigeoned analytics +09/04/1953 @ 09:24 -> 09/08/1953 @ 06:57 |Contentedness's perpendicular atmosphere +11/13/1953 @ 09:24 -> 11/17/1953 @ 03:12 |Hilbert's +04/01/1954 @ 05:40 -> 04/02/1954 @ 21:14 |Think equipment's sturdiness's birdbath's +06/16/1954 @ 01:30 -> 06/21/1954 @ 00:11 |Quotients prerequisite +02/06/1955 @ 07:45 -> 02/10/1955 @ 08:35 |Jami's shard's +07/19/1955 @ 04:27 -> 07/20/1955 @ 12:47 |Nanjing Apollonian heath's undeclared zinnia +08/13/1955 @ 15:47 -> 08/14/1955 @ 06:57 |Agglomerations wire Prescott's Mexicali extremer +09/18/1956 @ 21:45 -> 09/21/1956 @ 14:34 |Vouched Woodrow's +01/28/1957 @ 02:11 -> 01/28/1957 @ 07:56 |Intolerable cheekiness's reorganized blustering +05/13/1957 @ 17:09 -> 05/15/1957 @ 21:05 |Preferential blobbed Na +09/13/1957 @ 09:37 -> 09/16/1957 @ 11:59 |Reflexive +01/07/1958 @ 04:17 -> 01/07/1958 @ 18:53 |Slaver's bewared +05/13/1958 @ 09:54 -> 05/18/1958 @ 05:05 |Gentlest madcaps recaptures vestibule's +01/14/1959 @ 17:00 -> 01/18/1959 @ 19:12 |Stepchildren +05/21/1959 @ 23:01 -> 05/24/1959 @ 10:46 |Tailwind's preaches dappling ventricle's +07/19/1959 @ 10:37 -> 07/22/1959 @ 14:24 |Slingshot Cognac's insulate +01/03/1960 @ 05:18 -> 01/06/1960 @ 02:14 |Wren's carcinoma's jellied plateau engine's +03/06/1960 @ 21:51 -> 03/07/1960 @ 13:27 |Assessor cigar Bridges mutiny's freezing +04/13/1960 @ 20:14 -> 04/15/1960 @ 05:02 |Rios Hormel's +11/28/1960 @ 20:04 -> 11/28/1960 @ 22:29 |Sporran's extraordinaries Scotsmen findings +12/24/1960 @ 01:08 -> 12/27/1960 @ 20:51 |Meadows Alfredo valentine +08/01/1961 @ 08:23 -> 08/01/1961 @ 14:11 |Pavlova's misogynist munch instability temps +08/01/1962 @ 05:08 -> 08/03/1962 @ 15:28 |Betrothals Sexton's At's winced pilings +08/10/1962 @ 00:32 -> 08/10/1962 @ 07:04 |Quadruplets Karl dicks +03/13/1963 @ 06:02 -> 03/17/1963 @ 16:26 |Revitalization's Estelle's term +03/13/1963 @ 12:23 -> 03/14/1963 @ 21:32 |Moss executors +11/17/1963 @ 04:36 -> 11/21/1963 @ 00:04 |Overdid glassware charioteered +05/18/1964 @ 08:46 -> 05/20/1964 @ 21:54 |Demonstrated Shaffer's bobbling +07/13/1964 @ 18:48 -> 07/15/1964 @ 03:11 |Wingspans positing +07/20/1964 @ 06:56 -> 07/20/1964 @ 22:49 |Gizzard's galvanizing +09/09/1965 @ 20:38 -> 09/11/1965 @ 07:58 |Locomotion +01/18/1966 @ 00:24 -> 01/18/1966 @ 05:11 |Vamoose Madeira bishopric misstatement's +08/07/1966 @ 13:43 -> 08/12/1966 @ 08:03 |Parallelled penned samba's positron +08/23/1966 @ 09:52 -> 08/24/1966 @ 14:31 |Scrapes Cameroon's attorney Garbo's +09/24/1966 @ 03:39 -> 09/26/1966 @ 06:34 |Theater hosted condescend +02/22/1967 @ 22:10 -> 02/24/1967 @ 16:39 |Crossness Angelina's +09/09/1967 @ 10:23 -> 09/13/1967 @ 14:27 |Conservatory's crestfallen pluralized ornamental +10/26/1967 @ 01:46 -> 10/29/1967 @ 11:17 |Accelerated +02/10/1968 @ 11:09 -> 02/14/1968 @ 02:02 |Factions Sharpe's +05/08/1968 @ 06:25 -> 05/09/1968 @ 16:11 |Nesselrode's hiss preached shebangs +06/04/1969 @ 02:13 -> 06/04/1969 @ 10:49 |Wavelet +06/04/1969 @ 02:18 -> 06/09/1969 @ 05:29 |Dike's daylight's subtotalling indignation +06/07/1969 @ 22:31 -> 06/10/1969 @ 16:15 |Sex's seaway witch's vagina's +11/15/1969 @ 19:40 -> 11/17/1969 @ 14:24 |Hullabaloos brute's Fern's Milken's +01/23/1970 @ 18:06 -> 01/27/1970 @ 15:14 |Cowpoke's irrelevance +07/20/1970 @ 18:04 -> 07/23/1970 @ 22:25 |Undergrad's gondolas +11/02/1970 @ 15:52 -> 11/05/1970 @ 00:19 |Venting Shoshone's mockingbird fondly +11/15/1970 @ 23:51 -> 11/17/1970 @ 06:04 |Leftovers +11/30/1970 @ 20:13 -> 12/05/1970 @ 21:53 |Rhapsodizes protuberances whiplashes +06/02/1971 @ 01:13 -> 06/03/1971 @ 19:30 |Arbitration's +08/25/1971 @ 20:19 -> 08/27/1971 @ 19:16 |Consequently +11/15/1971 @ 06:06 -> 11/15/1971 @ 17:09 |Undercharging denseness acquitted arsonists euthanasia's +01/24/1972 @ 11:48 -> 01/28/1972 @ 20:16 |Ballsiest janitor +05/05/1972 @ 07:27 -> 05/05/1972 @ 09:42 |Molders saddening tenaciously Pruitt +09/28/1972 @ 07:26 -> 10/01/1972 @ 13:48 |Yank Armstrong skull's +10/19/1972 @ 11:35 -> 10/21/1972 @ 18:55 |Sadat billowed canvasser walrus Anabaptist +10/19/1972 @ 17:12 -> 10/22/1972 @ 05:39 |Clocks chance twiggiest cobra's sparest +10/26/1972 @ 19:47 -> 10/29/1972 @ 10:51 |Fibulae +04/13/1973 @ 23:53 -> 04/17/1973 @ 11:55 |Desalinated Kirby +06/22/1973 @ 06:55 -> 06/24/1973 @ 20:44 |Gibed conduit +10/05/1973 @ 05:46 -> 10/08/1973 @ 09:47 |Merriam Babel's Noreen pesetas +01/05/1974 @ 22:10 -> 01/06/1974 @ 10:56 |Busters scenic detoxified unfamiliar +01/15/1974 @ 10:29 -> 01/20/1974 @ 05:05 |Butterfly's examine unplugs sprucer dictations +01/24/1974 @ 05:57 -> 01/25/1974 @ 08:56 |Hefner's Marie's Mafias putt's enquiring +02/06/1974 @ 14:33 -> 02/10/1974 @ 18:59 |Issuance's lassoed beasts breakfasted confusingly +11/23/1974 @ 21:06 -> 11/24/1974 @ 12:30 |Squadron's +06/18/1975 @ 01:01 -> 06/23/1975 @ 08:17 |Trolleys Cameron pianist spelt southwestern +09/18/1975 @ 23:43 -> 09/19/1975 @ 09:11 |Unbuckles misfitted Cheshire disgracing +05/21/1976 @ 02:28 -> 05/23/1976 @ 09:35 |Premised graduations +07/31/1976 @ 21:40 -> 08/05/1976 @ 00:55 |Suffocation healthfulness rallied amulets satisfactorily +09/27/1976 @ 09:04 -> 09/30/1976 @ 09:21 |Adheres disintegrated harpoon's marooning peg +12/18/1976 @ 03:04 -> 12/21/1976 @ 02:02 |Pooching cuttlefishes imposture thorny +01/11/1977 @ 08:14 -> 01/13/1977 @ 09:51 |Landlords gabbles builder's laureating +03/09/1977 @ 01:24 -> 03/12/1977 @ 16:59 |Potboiler idiomatically +03/21/1977 @ 00:47 -> 03/21/1977 @ 17:00 |Deducible mailer Consuelo winging chameleon +12/09/1977 @ 20:35 -> 12/13/1977 @ 15:44 |Sosa swings +03/24/1978 @ 11:32 -> 03/27/1978 @ 17:26 |Wars Gregorio +02/13/1979 @ 20:48 -> 02/16/1979 @ 08:19 |Fidgets liquoring syphilis +03/15/1979 @ 07:42 -> 03/18/1979 @ 20:29 |Parking shoestrings disharmony's lassie +06/22/1979 @ 18:16 -> 06/26/1979 @ 11:16 |Stieglitz indiscreet visions buntings watchtower +08/20/1979 @ 12:01 -> 08/25/1979 @ 02:19 |Flushest Nate listen +11/20/1980 @ 17:22 -> 11/25/1980 @ 02:19 |Probability's inflexible mes sluggards +01/07/1981 @ 20:55 -> 01/09/1981 @ 23:19 |Flange internee inspector's +03/31/1981 @ 18:26 -> 04/05/1981 @ 07:44 |Sextets commits expectant +07/20/1982 @ 14:09 -> 07/23/1982 @ 21:59 |Vauban +10/12/1982 @ 08:50 -> 10/16/1982 @ 20:45 |Maltreated emulates popularize +10/25/1982 @ 07:17 -> 10/27/1982 @ 08:53 |Homeboy Velázquez Caesarean Mobil's Cheyenne's +12/13/1982 @ 22:30 -> 12/19/1982 @ 01:55 |Trellises binned hanky's Eurasia's destinies +12/31/1982 @ 01:21 -> 01/02/1983 @ 17:36 |Gyration's antiperspirant's +06/20/1983 @ 12:23 -> 06/24/1983 @ 17:32 |Deerskin +07/07/1983 @ 23:24 -> 07/11/1983 @ 02:42 |Gunnysacks heiress's cantons chase Polynesia's +11/01/1983 @ 23:44 -> 11/05/1983 @ 21:00 |Alexander cashier rays lackey filaments +11/16/1983 @ 21:22 -> 11/17/1983 @ 06:34 |Deflects reprinting flotillas marksmen haughtiness +01/01/1984 @ 23:49 -> 01/03/1984 @ 12:56 |Dissolutes Mobile's Ramsay's +02/11/1984 @ 18:24 -> 02/11/1984 @ 19:51 |Liqueur's lauds plighted +12/18/1985 @ 13:45 -> 12/19/1985 @ 02:48 |Filled pyrotechnics apostolic disorders +02/06/1986 @ 12:52 -> 02/06/1986 @ 16:07 |Concentric defense's +05/17/1986 @ 03:08 -> 05/21/1986 @ 01:12 |Render +12/18/1986 @ 02:38 -> 12/18/1986 @ 19:00 |Touchdowns Emory Doubleday's +12/24/1986 @ 11:06 -> 12/29/1986 @ 06:49 |Pontiffs horsewomen +01/03/1987 @ 23:12 -> 01/05/1987 @ 21:09 |Wraparounds tittling azimuth's +04/28/1987 @ 21:52 -> 05/03/1987 @ 12:14 |Commentary +08/03/1987 @ 21:11 -> 08/05/1987 @ 12:00 |Pinafore +10/30/1987 @ 22:05 -> 11/01/1987 @ 09:32 |Scourges +11/10/1987 @ 20:57 -> 11/15/1987 @ 22:00 |Orchards +12/20/1987 @ 08:50 -> 12/25/1987 @ 12:25 |Scapula's remounted scientist's Bonaventure +01/03/1988 @ 07:50 -> 01/07/1988 @ 15:22 |Idiom's propriety's averaging +07/07/1988 @ 13:29 -> 07/08/1988 @ 16:32 |Bushelled +09/11/1988 @ 04:09 -> 09/12/1988 @ 08:42 |Confrontational Olin's hoppers cede +12/20/1988 @ 13:08 -> 12/25/1988 @ 18:58 |Handouts that's +12/22/1988 @ 00:37 -> 12/27/1988 @ 07:42 |Uptight Greta's embellishment candider inquisitively +04/03/1989 @ 21:28 -> 04/04/1989 @ 16:15 |Klondiked undergoes plagiarize immediate +04/07/1989 @ 16:08 -> 04/10/1989 @ 16:16 |Flickers manly scrawniest commitments impeaches +05/05/1989 @ 03:46 -> 05/07/1989 @ 11:48 |Caesura's teeters rainy Neva +05/24/1990 @ 04:53 -> 05/27/1990 @ 12:13 |Mamma's bullshit's agglutinating +11/19/1990 @ 01:05 -> 11/21/1990 @ 11:00 |Krasnodar nick Jewell's +11/19/1990 @ 20:16 -> 11/25/1990 @ 02:42 |Boomed +08/30/1991 @ 00:12 -> 09/02/1991 @ 04:26 |Elwood soups motherhood's +10/25/1991 @ 14:11 -> 10/29/1991 @ 02:31 |Tyrannizing +05/19/1992 @ 04:00 -> 05/19/1992 @ 20:21 |Linkage ebbing naval aspect's unfailing +07/10/1992 @ 23:56 -> 07/12/1992 @ 17:03 |Vying +10/17/1992 @ 03:20 -> 10/19/1992 @ 13:54 |Hal aster roadway gristly +12/28/1992 @ 02:03 -> 12/30/1992 @ 13:21 |Sharks length's +02/05/1994 @ 23:07 -> 02/10/1994 @ 19:24 |Ameba's rested +07/15/1994 @ 13:55 -> 07/19/1994 @ 03:34 |Comically +09/18/1994 @ 23:20 -> 09/22/1994 @ 20:30 |Modeling Troy vixen's articulating evolutionary +10/27/1995 @ 03:19 -> 10/29/1995 @ 10:55 |Hindered collapse marched emphasis's +06/26/1996 @ 18:41 -> 06/30/1996 @ 02:34 |Hear peephole's +04/07/1997 @ 23:10 -> 04/10/1997 @ 06:55 |Folio's +06/12/1997 @ 16:27 -> 06/16/1997 @ 18:19 |Instantaneously toast's agreements warp +06/19/1997 @ 08:37 -> 06/24/1997 @ 06:56 |Undefined weeder sophism's allegory's sandpapers +07/21/1997 @ 12:35 -> 07/24/1997 @ 23:14 |Collided passerby sextants landlocked prudish +08/09/1997 @ 15:38 -> 08/12/1997 @ 05:17 |Transfixt Udall numbing subvert +09/08/1997 @ 23:21 -> 09/11/1997 @ 02:18 |Debbie Bolshevist ending +05/04/1998 @ 11:27 -> 05/06/1998 @ 17:19 |Optimism Arcturus's effectuating ratcheted +09/07/1998 @ 05:25 -> 09/12/1998 @ 03:42 |Deliriums +01/10/1999 @ 05:11 -> 01/13/1999 @ 02:03 |Holographs Rambo's +02/03/1999 @ 05:07 -> 02/07/1999 @ 02:36 |Louisianans jimmying artistes leased +05/20/1999 @ 03:37 -> 05/21/1999 @ 17:01 |Freeholder's +10/01/1999 @ 05:42 -> 10/04/1999 @ 04:09 |Notepaper's Abernathy's +11/17/1999 @ 19:43 -> 11/21/1999 @ 22:14 |Suicidal shirtwaist +12/19/1999 @ 18:55 -> 12/20/1999 @ 20:30 |Libellers +10/19/2000 @ 22:39 -> 10/20/2000 @ 04:55 |Plodder's moulting smokestacks instruments vagrancy's +05/30/2001 @ 10:07 -> 06/01/2001 @ 22:58 |Bulimia yank +12/02/2001 @ 22:03 -> 12/06/2001 @ 10:51 |Serviettes +01/24/2002 @ 09:14 -> 01/29/2002 @ 06:28 |Biddy +06/02/2002 @ 06:15 -> 06/05/2002 @ 15:12 |Thermoplastic Monroe's atrocity's Brandy's demoralizes +09/20/2002 @ 05:40 -> 09/24/2002 @ 21:32 |Guinevere's inspired limitation's +12/12/2002 @ 23:48 -> 12/14/2002 @ 04:07 |Disconcerted Osage observational +12/31/2002 @ 19:41 -> 01/01/2003 @ 12:21 |Tithes gig's +03/02/2003 @ 02:20 -> 03/03/2003 @ 21:24 |Editor's hazels epiglottises repercussion +03/23/2003 @ 20:46 -> 03/26/2003 @ 23:11 |Planter's Gambia Vietnamese +08/27/2003 @ 03:52 -> 08/30/2003 @ 10:56 |Dossier's MacArthur +01/11/2004 @ 15:57 -> 01/15/2004 @ 19:29 |Spindliest +05/10/2004 @ 09:21 -> 05/12/2004 @ 22:19 |Abrupt upbeats +05/14/2004 @ 17:37 -> 05/15/2004 @ 10:39 |Ordure's +07/02/2004 @ 20:21 -> 07/05/2004 @ 06:23 |Respectful superhighway +07/03/2004 @ 15:53 -> 07/03/2004 @ 17:39 |Magdalena unzip modernest Shapiro's Guerra +09/15/2005 @ 05:22 -> 09/19/2005 @ 02:03 |Newsed tarpons Boniface jocular +05/29/2006 @ 11:54 -> 06/03/2006 @ 02:31 |Sunsetting +02/17/2007 @ 18:09 -> 02/21/2007 @ 11:20 |Zorn centennial Domitian's nations overwrites +04/03/2007 @ 10:23 -> 04/04/2007 @ 04:01 |Humerus's organdy's Borobudur's escapist evaluations +05/17/2007 @ 05:37 -> 05/18/2007 @ 10:26 |Tallow's woodcarving Beijing potables +07/28/2007 @ 00:10 -> 07/31/2007 @ 00:52 |Dispirits composting willies hygrometers presaged +03/04/2008 @ 07:26 -> 03/06/2008 @ 18:45 |Deformation boggling brooms Episcopals trademarking +09/20/2008 @ 13:10 -> 09/25/2008 @ 09:28 |Recombining mantilla's lisped revisits +07/11/2009 @ 11:18 -> 07/14/2009 @ 12:43 |Sclerosis +08/17/2009 @ 01:46 -> 08/20/2009 @ 15:21 |Awkward +08/21/2009 @ 14:26 -> 08/22/2009 @ 08:26 |Defender's Chengdu cashew's Regor Deanne's +02/25/2010 @ 10:25 -> 02/27/2010 @ 05:20 |Optimums Hafiz's +07/15/2010 @ 08:43 -> 07/16/2010 @ 15:41 |Cyanide +07/20/2010 @ 11:56 -> 07/22/2010 @ 20:21 |Croup commode's geographical Ferber's Aguilar's +02/22/2011 @ 11:23 -> 02/26/2011 @ 07:21 |Covenants useful smoker's +06/15/2011 @ 05:21 -> 06/20/2011 @ 05:07 |Formative blissful experimentation's +07/14/2011 @ 09:43 -> 07/17/2011 @ 23:13 |Opens Tutankhamen's +04/02/2012 @ 03:57 -> 04/03/2012 @ 00:10 |Reexamines mugger's zephyr's morn's +04/07/2012 @ 16:05 -> 04/10/2012 @ 07:50 |Transpiration's sellout bleeds infusions spent +01/01/2013 @ 11:53 -> 01/05/2013 @ 21:24 |Rectum's charged cucumbers bashes outpatient's +02/10/2013 @ 21:23 -> 02/16/2013 @ 00:05 |Montezuma hairpins insetting Kochab's +08/19/2013 @ 18:34 -> 08/19/2013 @ 22:38 |Meteoroids +08/25/2013 @ 18:11 -> 08/29/2013 @ 13:50 |Lobotomy's quicksand familiarize Syracuse intermediary +04/22/2014 @ 23:15 -> 04/25/2014 @ 08:47 |Eastman vomited policemen fallacy adverbs +06/28/2014 @ 05:11 -> 07/02/2014 @ 10:33 |Bellyful's apportions +10/07/2014 @ 23:24 -> 10/12/2014 @ 00:19 |Misgoverned +01/15/2015 @ 15:38 -> 01/19/2015 @ 04:48 |Electrocutes cob truncates intrigued +05/28/2015 @ 07:38 -> 05/29/2015 @ 04:49 |Remount fragrance's +06/24/1912 [1] Flurry's docks courteously McKinley's apse's +07/01/1912 [1] Abrogates fraud's empty +07/16/1912 [1] Truckles vicissitudes +09/07/1943 [1] Transplant philologist's +04/29/1944 [1] Debases ammunition's fructifying tatty localing +08/02/1944 [1] Rescinds +10/29/1944 [1] Ascension's eighths democrat's wailing +01/14/1945 [1] Bevelling +08/01/1945 [1] Mortgagee doctrines robe's valedictories hermaphrodites +10/25/1945 [1] Amplitude's punctuating extraditing Mulroney +10/28/1945 [1] Canteens +06/10/1946 [1] Vows +03/30/1947 [1] Beaumont's Rothko +04/13/1947 [1] Jimmy derivation topographical evoking +09/14/1947 [1] Ga +04/30/1948 [1] Capitalization's flutist's +06/21/1948 [1] Besieger's spasmed Alcatraz's +08/13/1948 [1] Kaboom +10/26/1948 [1] Mummifying +02/02/1949 [1] Gadding Syria's +03/08/1949 [1] Unbridled Omayyad peacemaker's holocaust's +10/18/1949 [1] Sewing's juror trusted patrimony's +10/31/1949 [1] Cheever lily aerospace's fluffs +02/03/1950 [1] Congratulate legendary renovations unison's suburbanite +01/02/1951 [1] Savorier libertarians +01/21/1951 [1] Package uptown missive sphere moreover +03/07/1951 [1] Inmate mortgagee's stings +04/19/1951 [1] Borobudur's Clinton's censor +07/11/1951 [1] Lens Marcella's delimiter southerner's +07/31/1951 [1] Cockerel's +01/24/1952 [1] Mississauga Popper trachea's +05/10/1952 [1] Paroxysm flashiness's +07/19/1952 [1] Alcyone's temerity reclaimed Segre's soloing +09/17/1952 [1] Propaganda humanism Louisianians +11/10/1952 [1] Harper's mantissa's nautiluses +12/15/1952 [1] Brueghel's buddy Batista offensiveness +01/09/1953 [1] Visage Methodist Pontianak's +02/07/1953 [1] Roquefort's +07/13/1953 [1] Gandhian parsecs biathlon's reinstated +07/25/1953 [1] Depot carboy's unbosom +08/09/1953 [1] Gullet neighbor indelicacies +02/05/1954 [1] Drains defacement's +06/17/1954 [1] Virulently restrained +07/28/1954 [1] Sup soggy radishes Kinko +11/26/1954 [1] Firetrap's Ethernet +12/21/1954 [1] Airlifted womankind's Suetonius pities repatriation +12/22/1954 [1] Maurine Fanny's +02/06/1955 [1] Asphalt Aurora squidded pawnbroker leeward +02/20/1956 [1] Falter +09/06/1956 [1] Bisquick gimpiest imperialist +03/29/1957 [1] Conservators Coriolanus's +08/31/1957 [1] Socking parallaxes wellsprings kickiest escapades +11/08/1957 [1] Miniaturizing jail +11/21/1957 [1] Flintiest poplin's Clemson +08/13/1958 [1] Stiffen Swedenborg Hungarians +09/16/1958 [1] About stabilizing causals hesitates Bacardi's +12/21/1958 [1] Seymour Minnesotans qualms grungiest +04/21/1959 [1] Rime departing +05/21/1959 [1] Sectioning subleased Crecy's sloppiest +09/17/1959 [1] Beacon annuities pollywog's +11/21/1959 [1] Decency choreographers +06/21/1960 [1] Rosendo stipulates painter's +10/03/1960 [1] Convocations Klimt haft overstuffed whereon +12/10/1960 [1] Buber's habitual unholiest slue +03/27/1961 [1] Suffragists ova's marathoners creamery's +08/31/1961 [1] Cheesecake's pelts deicer normalcy +11/28/1961 [1] Nebula aureole's dictatorship's +06/13/1962 [1] Wire's pained +07/19/1962 [1] Salacious outskirt cloakroom's +10/21/1962 [1] Matricide's Underwood's +12/04/1962 [1] Sickness smudgiest legmen +08/04/1963 [1] McKnight's +09/04/1963 [1] Praised meltdowns Somalis +12/20/1963 [1] Instrumented Cordelia +05/22/1964 [1] Macedonian Bloomingdale's +06/27/1964 [1] Propagated basement +10/22/1964 [1] Yerevan's stinting teak apostate registrants +12/15/1964 [1] Whaler ants blooding vogue leopards +01/02/1965 [1] Accumulated Lucretia's Himalaya's driveway +03/24/1965 [1] Letha's +09/15/1965 [1] Plumes sensuous exigencies +12/08/1965 [1] Console +01/28/1966 [1] Samples preventible +02/08/1966 [1] Unpronounceable presuppose +03/15/1966 [1] Nominating comma cohered Catullus networking +05/06/1966 [1] Offenbach compatible insight redistrict +06/17/1966 [1] Antagonized kickers jockstrap's Minolta's +10/23/1966 [1] Copacabana +12/09/1966 [1] Uninterrupted handmaids incalculably flatly +12/30/1966 [1] Glimmerings relocatable differentiation Chesterfield's charcoal's +04/16/1967 [1] Vendor's exhausted Essie's rod +07/17/1967 [1] Squirrelled +07/20/1967 [1] Circumnavigation wackos gays inert nonuser +08/28/1967 [1] Trays Toltec's habituation +02/13/1968 [1] Murmuring sextons publisher's Ur's +04/13/1968 [1] Conduces +05/23/1968 [1] Protoplasm Afghan's +09/04/1968 [1] Castor's blarneyed +09/29/1968 [1] Wideness payees Shylock's Wycherley's smallest +01/08/1969 [1] Ageism debased gore excursion's +01/11/1969 [1] Dalian's brashness's deciding plagiarized Senior +01/19/1969 [1] Telecommutes Verdun's tonsillectomy +02/02/1969 [1] Croatia rococo's Cuvier's acknowledgment's +02/17/1969 [1] Closet drooled rollicking Amsterdam's Hegira +03/14/1969 [1] Uric Brazilian consult sweatiest +04/15/1969 [1] Struggle Blankenship's outcroppings +07/17/1969 [1] Meaner Martial +12/16/1969 [1] Skunk safekeepings canapé extraneous Brandeis's +03/17/1970 [1] Score +03/24/1970 [1] Macerate Isis brakeman Poltava +07/18/1970 [1] Menstruate bottled +12/16/1970 [1] Frothed dialog +12/28/1970 [1] Anther +01/29/1971 [1] Handicapper reversals +05/17/1971 [1] Aquinas +12/06/1971 [1] Loot lighthearted blindsiding Cleopatra tasty +04/12/1972 [1] Sponges prosperity's noncooperation +06/12/1972 [1] Stoplights vane's patients +06/14/1972 [1] Declaims fretting dissatisfaction's +09/24/1972 [1] Ravishing vulgarizes +10/19/1972 [1] Superiority's baptistery's antedate +11/07/1972 [1] Malignant duckbills mites peroxide's +10/19/1973 [1] Squishiest avalanches lark's muezzin's +01/21/1974 [1] Bismark's +02/03/1974 [1] Kyushu websites exhortation Melba's automaton's +05/09/1974 [1] Jehoshaphat albino overkilling Desdemona's +07/05/1974 [1] Tanked genitive +11/12/1974 [1] Cautiousness calamines lithium's fervidly chaperone's +01/15/1975 [1] Wringer unblocked audio's +02/18/1975 [1] Kebab's disarm Dramamine whittler lassitude's +04/21/1975 [1] Maroons loan's waist's daffodil +09/18/1975 [1] Hickey undetermined spray +12/23/1975 [1] Subordinating Cathay shambles +09/04/1976 [1] Silks blaze +10/27/1976 [1] Venturesome revoking debit +10/29/1976 [1] Inge scherzo's +12/28/1976 [1] Psychopath's unsure +01/23/1977 [1] Ally homographs raccoon's transubstantiation +02/08/1977 [1] Executable jiggles pickup reanimating grommet's +06/28/1977 [1] Politicized crape +08/30/1977 [1] Stylist's spooking Krupp's waterbeds gadfly +09/20/1977 [1] Ito's kegging resoundingly lore's +02/12/1978 [1] Cocky wasting menaces +05/06/1978 [1] Nurserymen keened acidifies Buford's +09/20/1978 [1] Rectifier's +09/22/1978 [1] Florine's gymnasia +02/06/1980 [1] Overreaches suborbital Madeleine +05/19/1980 [1] Overstatement synergy's +08/24/1980 [1] Efface herbicide Ramiro's +09/20/1980 [1] Unlikely testify Trondheim's +09/25/1980 [1] Jingoist's +03/26/1981 [1] Traverse +04/30/1981 [1] Settee's +05/09/1981 [1] Exhortations jelly's cabal +05/29/1981 [1] Extruding moseyed effusions auditor +07/21/1981 [1] Tobacco hypocrisy's slacks +08/05/1981 [1] Gabon's collying pays +11/11/1981 [1] Pickerel aboding aptness Poland +01/24/1982 [1] Farm's +02/03/1982 [1] Pantyhose +02/10/1982 [1] Knopf's Rachelle's Opel's innovation +02/17/1982 [1] Undergarments Elnora's +03/11/1982 [1] Husserl's Cd occurrences Jill's +10/14/1982 [1] Flamingo Sèvres selfsame disavowing +07/15/1983 [1] Electromagnetic implication's attachment's demagogue plighted +11/19/1983 [1] Nocturne +01/19/1984 [1] Deputation +06/05/1984 [1] Breaching Calvinists actuality's advertisement baritones +06/29/1984 [1] Miscalculated diluted +10/16/1984 [1] Ionosphere contiguity noisiness's +02/28/1985 [1] Mac requires corona mending's carpenters +05/28/1985 [1] Sandbox processor's overdraft's +12/15/1985 [1] Spruce +01/04/1986 [1] Atherosclerosis reinvents legerdemain's notation's +02/16/1986 [1] Narcissist +05/31/1986 [1] Fun jetting marquis felicity decathlon's +09/22/1986 [1] Bellhops June's bushing +12/20/1986 [1] Cockeyed weekending Chartres +01/30/1987 [1] Cornrowing heartburn's Lynn's cup resin +04/24/1987 [1] Guyana Punjabi's roisterer +07/11/1987 [1] Copped contract knacker's +07/19/1987 [1] Fencer's birthmark's reconstruct compellingly dissipates +10/03/1987 [1] Arden continents +12/04/1987 [1] Towns +01/20/1988 [1] Impetuously seeing's +08/18/1988 [1] Abhorrent cranial Cato surplice +09/12/1988 [1] Undecipherable Esperanza's +09/02/1989 [1] Imitations +12/22/1989 [1] Transmigrate +02/18/1990 [1] Precedence JFK distributing +06/21/1990 [1] Azimuth exhibits +08/30/1990 [1] Horsetails Heinlein's +12/14/1990 [1] Annoyances valuation +03/06/1991 [1] Knob delimit +05/21/1991 [1] Patriarchies churns vulcanized +01/25/1992 [1] Rag's province warding +12/08/1992 [1] Calking Thurmond's +05/07/1993 [1] Sledged sextants chance's +09/29/1993 [1] Masaryk diminuendo's Bond Moor's Bran's +10/04/1993 [1] Farthest sticklers chutes ragouts +10/16/1993 [1] Marcella Lindbergh firmware covers +06/03/1994 [1] Humps racier teat's cross stencil +08/20/1994 [1] Griffin's coauthor's +05/14/1995 [1] Curs nerdiest +02/29/1996 [1] Moo deviants snares overgrow +11/25/1996 [1] Pleasantries endears Wharton's encroaches +03/23/1997 [1] Kenneling G retorting branching's art +07/07/1997 [1] Shillelagh keens tritely Rodin's +11/12/1997 [1] Taklamakan +12/14/1997 [1] Speakeasies lashing's cancellations Boleyn's +05/04/1998 [1] Resplendently dose insufficiency's day's +05/24/1998 [1] Expeditionary +08/29/1998 [1] Deleted richer Japura's whetstone's +11/02/1998 [1] Truncating reproof's restating dignity's chi's +11/07/1998 [1] Meaty bubbles establishing versification +12/20/1998 [1] Gladlier friendliest +03/20/1999 [1] Floating consonant's hobbyhorse's Tahiti scimitar +05/30/1999 [1] Raid insulation colorfully mandibles +04/07/2000 [1] Chapping bequeaths satellites +05/17/2000 [1] Her Peron gavels footbridge's bacchanal's +07/10/2000 [1] Leaved mime's saltwater +08/04/2000 [1] Margins charting edgy personae +01/25/2001 [1] Accurateness hoed flakiness's +02/26/2001 [1] Toolboxes circularized +12/08/2001 [1] Overspill's Waikiki's cowlicks redirecting +08/06/2003 [1] Carbide's downscales glamorized geometrical mitten +09/01/2003 [1] Pedagoguing doll's outlet's +01/15/2004 [1] Communities packers pinch +06/21/2004 [1] Rush's +07/03/2004 [1] Chariot Hornblower's +11/09/2004 [1] Unforgivable exhorting demolish irrecoverable clearing +11/21/2004 [1] Silicone +12/07/2004 [1] Rheumier easiest Andrew's abbots +04/10/2005 [1] Cindy's palette gnash +10/19/2005 [1] Mazes +03/13/2006 [1] Midwinter unobstructed Ginger's incumbents +06/08/2006 [1] Eulogistic decoding groveling Alcibiades plankton +06/27/2006 [1] Randomizes berthing hurdles +07/21/2006 [1] Montaigne's reverie's niceness beats goading +08/19/2006 [1] Northerner rebuffing impalas rooftops +09/27/2006 [1] Cargo reversion Khan's Episcopalian semicircle +08/24/2007 [1] Elucidations ritzy panting +04/30/2008 [1] Accountability +10/06/2008 [1] Cosponsor chored +11/24/2008 [1] Wizard's Galahad's +12/17/2008 [1] Incivility erratically Hermite +02/14/2009 [1] Harpsichord mortgagers oldened +02/14/2009 [1] Pliers Suzanne Johns Olga's tripling +03/13/2009 [1] Environmentalist malts toxicology's Gadsden's +03/25/2009 [1] Administered warranty whirling +09/18/2009 [1] Methanol ilks +12/08/2009 [1] Poetic cadre abasement campground's extinguish +02/26/2010 [1] Maturer wantoning +08/16/2010 [1] Esau's brainchildren +08/21/2010 [1] Agreeably Brigham's misalignment +11/12/2010 [1] Humidified Rockford's keynote churlish +02/25/2011 [1] Socket ghastlier +04/10/2011 [1] Detrimental +05/05/2011 [1] Access imbibe +09/02/2011 [1] Gorgas flaunts parched +12/28/2011 [1] Collaboration Tenochtitlan's rapscallion psychologist's extincting +05/20/2012 [1] Trots lorry +06/03/2012 [1] Hoorayed assignment +06/11/2012 [1] Ah drifter's +04/26/2013 [1] Donald's +07/19/2013 [1] Woodcutter sanctimonious nightfall's crews +03/03/2014 [1] Uncoupling cabarets gondolier's +08/22/2014 [1] Pelleted discrepancies +10/15/2014 [1] Fizzling +03/14/2015 [1] Damneder poking markdown quagmire's +01/10/2016 [1] Hireling spellers +08/30/2016 [1] Gaffe's shrinks +10/01/2016 [1] Plenipotentiaries snooker calcified fileting Bessemer's +12/18/2016 [1] Acidity vaults +02/24/2017 [1] Psyched Sondra's +03/12/2017 [1] Nark sacristan's +04/06/2017 [1] Titanium +06/22/2017 [1] Tub grenadier's longing's gram's +08/19/2017 [1] Twaddling +06/07/2018 [1] Uppity +06/28/2018 [1] Retarded Ginsburg's nonce's +12/17/2018 [1] Succored desperadoes ascend +03/02/2019 [1] Silence Joy's keener consciousnesses +04/07/2019 [1] Beck's Ariosto's +04/30/2019 [1] Stepsister's +08/25/2020 [1] Ideas Gershwin +11/07/2020 [1] Slackening slovenlier reel +11/12/2020 [1] Oration's +12/29/2020 [1] Keep +03/02/2021 [1] Stockyard's consummation equivocates +03/31/2021 [1] Irruptions blatant Monteverdi's medicinals Woolworth +04/18/2021 [1] Assailing +08/08/2021 [1] Interfaith overwhelmingly afflicts posteriors Erasmus's +04/03/2022 [1] Inundating yuckiest technician tetrahedron's foresails +08/15/2022 [1] Heralded F stroked +10/09/2022 [1] Sixes unafraid decoded +11/28/2022 [1] Stupefied blips +06/26/2023 [1] Supplicate Terri +10/11/2023 [1] Boyishness's intuitive cask's Armageddon's +06/21/2024 [1] Sepulcher Bacall +06/27/2024 [1] Slivering +08/05/2024 [1] Dempsey's Intel's +04/04/2025 [1] Directorate inoffensive +04/25/2025 [1] Waddle saintliness's Mercia's denseness +05/15/2025 [1] Intensity hydrology Peel power +11/19/2025 [1] Wingspans affluence's +02/20/2026 [1] Dicky impersonator +03/20/2026 [1] Boneless rilling +05/11/2026 [1] Carnations nigger's +11/17/2026 [1] Barrios slicker's thirty's +03/26/2027 [1] Dizziest Kerry Ndjamena's pizzicato +04/06/2027 [1] Parenthetical chemotherapy +10/02/2027 [1] Provender's limericks +03/21/2028 [1] Dent nape's unevener irradiated denizen's +03/23/2028 [1] Tailgated gawkiness's +05/07/2028 [1] Elope hammerings complexioned +07/15/2028 [1] Describe hooter Surat's paramedicals +09/11/2028 [1] Inc videotaped sixteenth eyeliner +09/12/2028 [1] Resend sake sundries rumbaing +11/03/2029 [1] Blisters willful +11/07/2029 [1] Mascaraing assertive vulnerably pruned +11/30/2029 [1] O'Hara wrench elm +01/08/2030 [1] Cashier's sherbet earwax's stiffeners +05/07/2030 [1] Compatibles Joyner asynchronous +07/01/2030 [1] Empire's entwine +03/25/2031 [1] Proverbially unwarranted effectiveness +04/16/2031 [1] Nosedives pennon's disburse scalloping +07/01/2031 [1] Surrealist guppy unabated Gwendoline +07/21/2031 [1] Casting's carelessness Anselmo's +10/03/2031 [1] Autos +11/09/2031 [1] Cockscomb's +12/18/2031 [1] Succumb Key's Cossacks blackness +01/24/2032 [1] Sidelined yell +01/31/2032 [1] Thebes determining glutting manorial Barbra +04/27/2032 [1] Cringing Osborne +05/26/2032 [1] Confine lames +08/03/2032 [1] Ceremonial straw's antelope's Mercer Kathiawar's diff --git a/test/data/conf b/test/data/conf new file mode 100644 index 0000000..de5efd0 --- /dev/null +++ b/test/data/conf @@ -0,0 +1,75 @@ +# +# Calcurse configuration file +# +# This file sets the configuration options used by Calcurse. These +# options are usually set from within Calcurse. A line beginning with +# a space or tab is considered to be a continuation of the previous line. +# For a variable to be unset its value must be blank, followed by an +# empty line. To set a variable to the empty string its value should be "". +# Lines beginning with "#" are comments, and ignored by Calcurse. + +# If this option is set to yes, automatic save is done when quitting +general.autosave=yes + +# If this option is set to yes, the GC is run automatically when quitting +general.autogc=no + +# If not null, perform automatic saves every 'periodic_save' minutes +general.periodicsave=0 + +# If this option is set to yes, confirmation is required before quitting +general.confirmquit=yes + +# If this option is set to yes, confirmation is required before deleting an event +general.confirmdelete=yes + +# If this option is set to yes, messages about loaded and saved data will not be displayed +general.systemdialogs=no + +# If this option is set to yes, progress bar appearing when saving data will not be displayed +general.progressbar=no + +# Default calendar view (0)monthly (1)weekly: +appearance.calendarview=0 + +# If this option is set to yes, monday is the first day of the week, else it is sunday +general.firstdayofweek=monday + +# This is the color theme used for menus : +appearance.theme=red on default + +# This is the layout of the calendar : +appearance.layout=1 + +# Width ( percentage, 0 being minimun width, fp) of the side bar : +appearance.sidebarwidth=1 + +# If this option is set to yes, notify-bar will be displayed : +appearance.notifybar=yes + +# Format of the date to be displayed inside notify-bar : +format.notifydate=%a %F + +# Format of the time to be displayed inside notify-bar : +format.notifytime=%T + +# Warn user if he has an appointment within next 'notify-bar_warning' seconds : +notification.warning=300 + +# Command used to notify user of an upcoming appointment : +notification.command=printf '\a' + +# Notify all appointments instead of flagged ones only +notification.notifyall=no + +# Format of the date to be displayed in non-interactive mode : +format.outputdate=%D + +# Format to be used when entering a date (1)mm/dd/yyyy (2)dd/mm/yyyy (3)yyyy/mm/dd) (4)yyyy-mm-dd: +format.inputdate=1 + +# If this option is set to yes, calcurse will run in background to get notifications after exiting +daemon.enable=no + +# If this option is set to yes, activity will be logged when running in background +daemon.log=no diff --git a/test/data/todo b/test/data/todo new file mode 100644 index 0000000..6f1c0e0 --- /dev/null +++ b/test/data/todo @@ -0,0 +1,197 @@ +[7] Wheeling predictor aggrieve dentist's vegetable +[-8] Stine's Napier's +[9] Gloriously slams +[-6] Reigning +[5] Television +[3] Aladdin ancestoring matzohs +[-8] Holloway's turnip's +[1] Nary parabled Louvre's fleetest mered +[-7] Josef heir's flake +[-4] Spins Mondrian's velveteen +[-7] Phone's backrest's +[2] Surgical handlers fodder Crimea +[-1] Finality surging studentship inversely terry +[-3] Knitwear's cruet +[-6] Scalper board coalescence's speedsters Tabatha's +[6] Apprehend domino Olivier's +[7] Acid bicepses magnetizing Trotsky's +[-9] Tugboat warrantying +[4] Restrictive Gresham clinch thunderhead +[1] Stench's approximates torus's gymnast's +[-5] Sixteen's +[-6] Pear bauble clemency's heartbreaks compresses +[-8] Bytes asters +[2] Freebasing Oppenheimer +[8] Secessionists Keogh's +[-6] Mass analog's Pharaoh's sensationalists +[-7] Dissidence +[4] Unbuttoned horsemen beggar's commander Griffin +[-6] Computations Yangtze slowpokes sourly bearskin's +[2] Finesses Sebastian's nightclubbed +[6] Rectangle mascots examiner blah screechy +[-3] Electrolyte equities infrastructure's +[2] Daydreamed +[5] Globed +[-2] Stores shamefaced slithering +[5] Reverend +[7] Proposed trespassed Bultmann +[3] Maui +[7] Restarts poisoner's Patterson's bucktooth +[3] Dislodged washboard inhabitant's +[5] Unsafer ingenuousness's supine +[-4] Ripeness's nirvana +[-7] Invigorating desserts copy's abbé +[-5] Shorthorns straddle carbons +[6] Lading +[-2] Drawling secretary's +[6] Ransom tablet +[3] Unbarring +[1] Uncorks aggression's Charmaine +[-1] Donor's mummers dunning +[-4] Leafiest tomcats crematoria Teletypes quires +[-7] Koshered numismatics's +[3] Wavelet's anapests flan +[8] Stroke farmyard's deterrent urned +[-6] Gunsmiths +[8] Chileans smirk footholds +[4] Erasmus pawnshop unmasked Andromache transgression's +[4] Heighten squirted +[-7] Hoodwinks Hector Playboy's fizzy +[1] Fillmore's ricks Federico kiloton's steamy +[5] Thor songwriters hookup +[-1] Chatty +[-6] Insensitivity shrill vainly Schindler's installs +[1] Originality channeled romantically +[-2] Advil +[9] Beefburger's +[2] Chorals incurred rediscovery's dioxide's firstly +[8] Designed breach salarying +[1] Phantom's Tagore +[-4] Harriet worlds +[5] Thereby +[-2] Edgewise +[8] Pleasanter +[1] Kindness redundant +[5] Soto's thrones tracing's +[-2] Jenner's cymbal's +[8] Surreals Zachery demonstrative athlete's +[-9] Roommate +[-1] Amening Hofstadter's excellently +[-4] Refining wildest +[2] Sudan's Ger's +[3] Yukon's expletives +[6] Cox foretold electroencephalogram gargoyle individualizing +[6] Speedier buzzer Natalia +[2] Sphinx telepathy's +[1] Nahum run debauches chambers +[-7] Extortion cacophonies +[4] Maharajas +[3] Virtuosi incompatible +[7] Timex's Semarang undercarriage gladiator +[-6] Meditates choreographing +[-2] Indianapolis career +[-8] Sensuality's pushover's bookkeeper's democrat's Establishment's +[-7] Sputtering Liz gentle +[8] Consonances wounding petties confessors blaze's +[-8] Pentateuch's acquiting clumsiest +[4] Angstrom +[7] Watson sepsis's depoliticizing wried La's +[-6] Terrapins +[9] Seasons +[-5] Bumpier drolly Sallust maws +[1] Overstayed +[-9] Sheer +[6] Arrayed jewelling +[8] Distrusted crinkly tels +[8] Wilier allegro dine dead +[-3] Sores brokerage prerecorded Clifton's +[8] Anyone Rowena's rumbled +[-1] Chairlift's abstruse Baikal mattresses dowry's +[5] Diaz's disrespected washtub's +[6] Eisner's conditioning +[-7] Ape's +[-9] Flirts provocative Liechtenstein mozzarella butterfat's +[3] Homeopathy triennials potteries ovoid +[2] Perpetrators hypnotize Iliad's personalizes dike +[5] Olympia's Esperanto's +[2] Receptors instil unripe +[7] Groggier +[-9] Journalists +[-8] Creator +[2] Brownsville +[-2] Breadwinner sulfides +[-7] Canoe impenetrable scrolled +[4] Figurehead's nurture +[7] Colombia Brahe's Johnston's spectacle jailors +[-5] Strawberries syllogism +[-1] Skimping brotherliness underscoring provendered +[-2] Augment Husserl's unselfishness apostle +[-2] Angle manipulates +[-8] Other attempts +[-6] Cook's scouring eh perimeter tomahawked +[1] Metropolises leg's ultimated inseminating minaret's +[2] Streptomycin's characterization's mercies entry's montage +[1] Hooky niggards +[-8] Embroidered Burton's cleave +[1] Sharon preponderances hostessing inimitable +[8] Briefcase +[-9] Sparta's reappraisals whiniest Jocasta's curator's +[-9] Becalm careers carotids +[4] Inundate +[6] Butchery piling's infomercial +[3] Delineated +[5] Unfinished surfs +[-8] Recourse's +[-6] Airtight overshot contest's ostentation +[8] Roadshow bit's confection pastors wenches +[-2] Saussure unselfish +[-3] Guy insulation's maria's +[7] Observers +[-2] Decomposition's registry inboards crowbars +[-1] Dahomey's facilitation's +[-8] Ehrlich laced countertenor's convergence's choices +[-2] Crochet +[1] Defiance's cliffhangers battery +[6] Multiplex +[6] Springfield directs framer's empties +[-3] Blunderbuss's +[-4] Flusters allegiance's +[-5] Trawled +[5] Carrousels Avalon's +[7] Constantine's ladings +[-1] Regencies requires monkeyshines pornographic +[7] Trolling +[1] Promontory's mutts silk disc's foot +[8] Vibrating +[-8] Homeyness hibernates sambas fierceness's +[8] Noise's quadruplicating multimedia Lyell +[3] Equilaterals shes minibuses nudity consolidates +[6] Hernia coccyges Orlon's Nirenberg +[-2] Soakings Armagnac sexuality's homelier pests +[7] Peso chalk's abiding +[-6] Portraiture littoral leavening +[-9] Boatman fleetingly radiator +[3] Sissy husks +[-7] Swearers gauntlets deepness acclaims stimulate +[-1] Comedown +[-9] Jubal's +[1] Town vigor alphabetical concluded +[-2] Baroda gazpacho's jolliness resupplies +[-9] Asked +[3] Chandrasekhar's gunfire's Earp's +[-3] Bickering's shorts eagerness +[-6] Ambiances Gagarin's milksops gargle +[-5] Rainforest rediscovered Bohemia +[-3] Syntactics smokehouses downward Quirinal reoccupy +[-9] Succored sweetbriers +[-4] Profess dismemberment fly syndicate +[-4] Billeting +[-9] Streetwalker's +[4] Haberdashery's rates tentative eBay's McCoy +[-3] Al's butterflying ovulate recitatives lumbered +[2] Eye treads Eng's Peron baize +[3] Podded +[-9] Plunderer heightened spindlier transiting +[-7] Pared +[-5] Blueprint's gemstone's ceremony anteater's +[3] Quarters diff --git a/test/day-001.sh b/test/day-001.sh new file mode 100755 index 0000000..614f6e3 --- /dev/null +++ b/test/day-001.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +if [ "$1" = 'actual' ]; then + "$CALCURSE" --read-only -D "$DATA_DIR"/ -d02/25/2011 +elif [ "$1" = 'expected' ]; then + cat <<EOD +02/25/11: + * Socket ghastlier + - ..:.. -> ..:.. + Covenants useful smoker's +EOD +else + ./run-test "$0" +fi diff --git a/test/day-002.sh b/test/day-002.sh new file mode 100755 index 0000000..66ebabd --- /dev/null +++ b/test/day-002.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +if [ ! -x "$(command -v faketime)" ]; then + echo "libfaketime not found - skipping $0..." + exit 1 +fi + +if [ "$1" = 'actual' ]; then + faketime '1912-06-23' "$CALCURSE" --read-only -D "$DATA_DIR"/ -d42 +elif [ "$1" = 'expected' ]; then + cat <<EOD +06/24/12: + * Flurry's docks courteously McKinley's apse's + +07/01/12: + * Abrogates fraud's empty + +07/10/12: + - 17:47 -> ..:.. + Impersonating integer broils blame + +07/11/12: + - ..:.. -> ..:.. + Impersonating integer broils blame + +07/12/12: + - ..:.. -> ..:.. + Impersonating integer broils blame + +07/13/12: + - ..:.. -> 03:18 + Impersonating integer broils blame + +07/16/12: + * Truckles vicissitudes +EOD +else + ./run-test "$0" +fi diff --git a/test/day-003.sh b/test/day-003.sh new file mode 100755 index 0000000..7534cd8 --- /dev/null +++ b/test/day-003.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +if [ ! -x "$(command -v faketime)" ]; then + echo "libfaketime not found - skipping $0..." + exit 1 +fi + +if [ "$1" = 'actual' ]; then + faketime '1912-06-23' "$CALCURSE" --read-only -D "$DATA_DIR"/ -d42 +elif [ "$1" = 'expected' ]; then + "$CALCURSE" --read-only -D "$DATA_DIR"/ -s06/23/1912 -r42 +else + ./run-test "$0" +fi diff --git a/test/next-001.sh b/test/next-001.sh new file mode 100755 index 0000000..85ebd63 --- /dev/null +++ b/test/next-001.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +if [ ! -x "$(command -v faketime)" ]; then + echo "libfaketime not found - skipping $0..." + exit 1 +fi + +if [ "$1" = 'actual' ]; then + faketime '1912-07-10 04:10' "$CALCURSE" --read-only -D "$DATA_DIR" -n +elif [ "$1" = 'expected' ]; then + cat <<EOD +next appointment: + [13:37] Impersonating integer broils blame +EOD +else + ./run-test "$0" +fi diff --git a/test/range-001.sh b/test/range-001.sh new file mode 100755 index 0000000..8f23876 --- /dev/null +++ b/test/range-001.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +if [ ! -x "$(command -v faketime)" ]; then + echo "libfaketime not found - skipping $0..." + exit 1 +fi + +if [ "$1" = 'actual' ]; then + faketime '2011-02-25 00:00:00' "$CALCURSE" --read-only -D "$DATA_DIR"/ -r +elif [ "$1" = 'expected' ]; then + cat <<EOD +02/25/11: + * Socket ghastlier + - ..:.. -> ..:.. + Covenants useful smoker's +EOD +else + ./run-test "$0" +fi diff --git a/test/range-002.sh b/test/range-002.sh new file mode 100755 index 0000000..0610017 --- /dev/null +++ b/test/range-002.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +if [ ! -x "$(command -v faketime)" ]; then + echo "libfaketime not found - skipping $0..." + exit 1 +fi + +if [ "$1" = 'actual' ]; then + faketime '2000-01-01 00:00:00' "$CALCURSE" --read-only -D "$DATA_DIR"/ -r400 +elif [ "$1" = 'expected' ]; then + cat <<EOD +04/07/00: + * Chapping bequeaths satellites + +05/17/00: + * Her Peron gavels footbridge's bacchanal's + +07/10/00: + * Leaved mime's saltwater + +08/04/00: + * Margins charting edgy personae + +10/19/00: + - 22:39 -> ..:.. + Plodder's moulting smokestacks instruments vagrancy's + +10/20/00: + - ..:.. -> 04:55 + Plodder's moulting smokestacks instruments vagrancy's + +01/25/01: + * Accurateness hoed flakiness's +EOD +else + ./run-test "$0" +fi diff --git a/test/range-003.sh b/test/range-003.sh new file mode 100755 index 0000000..a291208 --- /dev/null +++ b/test/range-003.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +if [ ! -x "$(command -v faketime)" ]; then + echo "libfaketime not found - skipping $0..." + exit 1 +fi + +if [ "$1" = 'actual' ]; then + faketime '2000-01-01 00:00:00' "$CALCURSE" --read-only -D "$DATA_DIR"/ -r400 +elif [ "$1" = 'expected' ]; then + "$CALCURSE" --read-only -D "$DATA_DIR"/ -s01/01/2000 -r400 +else + ./run-test "$0" +fi diff --git a/test/run-test-001.sh b/test/run-test-001.sh new file mode 100755 index 0000000..9c1a962 --- /dev/null +++ b/test/run-test-001.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ "$1" = 'actual' -o "$1" = 'expected' ]; then + echo 42 +else + ./run-test "$0" +fi diff --git a/test/run-test-002.sh b/test/run-test-002.sh new file mode 100755 index 0000000..6a10101 --- /dev/null +++ b/test/run-test-002.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +if [ "$1" = 'actual' ]; then + echo 23 +elif [ "$1" = 'expected' ]; then + echo 42 +else + ./run-test "!$0" +fi diff --git a/test/run-test.c b/test/run-test.c new file mode 100644 index 0000000..c779be7 --- /dev/null +++ b/test/run-test.c @@ -0,0 +1,229 @@ +/* + * 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 <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/wait.h> + +/* + * Fork and execute an external process. + * + * If pfdin and/or pfdout point to a valid address, a pipe is created and the + * appropriate file descriptors are written to pfdin/pfdout. + */ +static int +fork_exec(int *pfdin, int *pfdout, const char *path, char *const *arg) +{ + int pin[2], pout[2]; + int pid; + + if (pfdin && (pipe(pin) == -1)) + return 0; + if (pfdout && (pipe(pout) == -1)) + return 0; + + if ((pid = fork()) == 0) { + if (pfdout) { + if (dup2(pout[0], STDIN_FILENO) < 0) + _exit(127); + close(pout[0]); + close(pout[1]); + } + + if (pfdin) { + if (dup2(pin[1], STDOUT_FILENO) < 0) + _exit(127); + close(pin[0]); + close(pin[1]); + } + + execvp(path, arg); + _exit(127); + } else { + if (pfdin) + close(pin[1]); + if (pfdout) + close(pout[0]); + + if (pid > 0) { + if (pfdin) { + fcntl(pin[0], F_SETFD, FD_CLOEXEC); + *pfdin = pin[0]; + } + if (pfdout) { + fcntl(pout[1], F_SETFD, FD_CLOEXEC); + *pfdout = pout[1]; + } + } else { + if (pfdin) + close(pin[0]); + if (pfdout) + close(pout[1]); + return 0; + } + } + return pid; +} + +/* Wait for a child process to terminate. */ +static int child_wait(int *pfdin, int *pfdout, int pid) +{ + int stat; + + if (pfdin) + close(*pfdin); + if (pfdout) + close(*pfdout); + + waitpid(pid, &stat, 0); + return stat; +} + +/* Print error message and bail out. */ +static void die(const char *format, ...) +{ + va_list arg; + + va_start(arg, format); + fprintf(stderr, "error: "); + vfprintf(stderr, format, arg); + va_end(arg); + + exit(1); +} + +/* Print usage message. */ +static void usage(void) +{ + printf("usage: run-test [-h|--help] <test>...\n"); +} + +/* Run test with a specific name. */ +static int run_test(const char *name, int expect_failure) +{ + char filename[BUFSIZ]; + char *arg1[3], *arg2[3]; + int pid1 = -1, pin1, pid2 = -1, pin2; + FILE *fpin1 = NULL, *fpin2 = NULL; + char buf1[BUFSIZ], buf2[BUFSIZ]; + int ret = 1; + + if (snprintf(filename, BUFSIZ, "./%s", name) >= BUFSIZ) + die("file name too long\n"); + + if (access(filename, F_OK) != 0) { + if (snprintf(filename, BUFSIZ, "./%s.sh", name) >= BUFSIZ) + die("file name too long\n"); + + if (access(filename, F_OK) != 0) + die("test not found: %s\n", name); + } + + if (access(filename, X_OK) != 0) + die("script is not executable: %s\n", filename); + + arg1[0] = arg2[0] = filename; + arg1[1] = "expected"; + arg2[1] = "actual"; + arg1[2] = arg2[2] = NULL; + + printf("Running %s...", name); + + if ((pid1 = fork_exec(&pin1, NULL, *arg1, arg1)) < 0) + die("failed to execute %s: %s\n", filename, strerror(errno)); + + if ((pid2 = fork_exec(&pin2, NULL, *arg2, arg2)) < 0) + die("failed to execute %s: %s\n", filename, strerror(errno)); + + fpin1 = fdopen(pin1, "r"); + fpin2 = fdopen(pin2, "r"); + + while (fgets(buf1, BUFSIZ, fpin1)) { + if (!fgets(buf2, BUFSIZ, fpin2) || strcmp(buf1, buf2) != 0) { + ret = 0; + break; + } + } + + if (fpin1) + fclose(fpin1); + if (fpin2) + fclose(fpin2); + + if (child_wait(&pin1, NULL, pid1) != 0) + ret = 0; + if (child_wait(&pin2, NULL, pid2) != 0) + ret = 0; + + if (expect_failure) + ret = 1 - ret; + + if (ret == 1) + printf(" ok\n"); + else + printf(" FAIL\n"); + + return ret; +} + +int main(int argc, char **argv) +{ + int i; + + if (!argv[1]) + die("no tests specified, bailing out\n"); + else if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { + usage(); + return 0; + } + + for (i = 1; i < argc; i++) { + if (*argv[i] == '!') { + if (!run_test(argv[i] + 1, 1)) + return 1; + } else { + if (!run_test(argv[i], 0)) + return 1; + } + } + + return 0; +} diff --git a/test/search-001.sh b/test/search-001.sh new file mode 100755 index 0000000..2d8f7e8 --- /dev/null +++ b/test/search-001.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +if [ ! -x "$(command -v faketime)" ]; then + echo "libfaketime not found - skipping $0..." + exit 1 +fi + +if [ "$1" = 'actual' ]; then + "$CALCURSE" --read-only -D "$DATA_DIR"/ -s01/01/1902 -r36500 \ + -S '^[KMS]an.*or' +elif [ "$1" = 'expected' ]; then + cat <<EOD +12/06/42: + - 09:46 -> ..:.. + Manuel glorified four + +12/07/42: + - ..:.. -> 04:33 + Manuel glorified four + +05/28/85: + * Sandbox processor's overdraft's +EOD +else + ./run-test "$0" +fi diff --git a/test/todo-001.sh b/test/todo-001.sh new file mode 100755 index 0000000..db6b6ca --- /dev/null +++ b/test/todo-001.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ "$1" = 'actual' ]; then + "$CALCURSE" --read-only -D "$DATA_DIR"/ -t | sort +elif [ "$1" = 'expected' ]; then + ( + echo 'to do:' + sed '/^\[-/d; s/^\[\([0-9]\)\] \(.*\)/\1. \2/' "$DATA_DIR"/todo + ) | sort +else + ./run-test "$0" +fi diff --git a/test/todo-002.sh b/test/todo-002.sh new file mode 100755 index 0000000..a91d06d --- /dev/null +++ b/test/todo-002.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +if [ "$1" = 'actual' ]; then + "$CALCURSE" --read-only -D "$DATA_DIR"/ -t3 +elif [ "$1" = 'expected' ]; then + echo 'to do:' + sed -n 's/^\[3\] \(.*\)/3. \1/p' "$DATA_DIR"/todo +else + ./run-test "$0" +fi diff --git a/test/todo-003.sh b/test/todo-003.sh new file mode 100755 index 0000000..2dcb2d3 --- /dev/null +++ b/test/todo-003.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ "$1" = 'actual' ]; then + "$CALCURSE" --read-only -D "$DATA_DIR"/ -t0 | sort -n +elif [ "$1" = 'expected' ]; then + ( + echo 'completed tasks:' + sed -n 's/^\[-\([0-9]\)\] \(.*\)/\1. \2/p' "$DATA_DIR"/todo + ) | sort -n +else + ./run-test "$0" +fi diff --git a/test/true-001.sh b/test/true-001.sh new file mode 100755 index 0000000..296ef78 --- /dev/null +++ b/test/true-001.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +true |