diff options
-rw-r--r-- | TODO | 9 | ||||
-rw-r--r-- | doc/Makefile.am | 5 | ||||
-rw-r--r-- | doc/calcurse.1.txt | 3 | ||||
-rw-r--r-- | doc/manual.txt | 13 | ||||
-rw-r--r-- | doc/submitting-patches.txt | 192 | ||||
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/apoint.c | 140 | ||||
-rw-r--r-- | src/args.c | 107 | ||||
-rw-r--r-- | src/calcurse.c | 283 | ||||
-rw-r--r-- | src/calcurse.h | 266 | ||||
-rw-r--r-- | src/calendar.c | 64 | ||||
-rw-r--r-- | src/custom.c | 460 | ||||
-rw-r--r-- | src/day.c | 274 | ||||
-rw-r--r-- | src/dmon.c | 19 | ||||
-rw-r--r-- | src/event.c | 43 | ||||
-rw-r--r-- | src/getstring.c | 299 | ||||
-rw-r--r-- | src/help.c | 75 | ||||
-rw-r--r-- | src/io.c | 650 | ||||
-rw-r--r-- | src/keys.c | 65 | ||||
-rw-r--r-- | src/llist.c | 33 | ||||
-rw-r--r-- | src/llist.h | 7 | ||||
-rw-r--r-- | src/llist_ts.h | 6 | ||||
-rw-r--r-- | src/mem.c | 30 | ||||
-rw-r--r-- | src/note.c | 235 | ||||
-rw-r--r-- | src/notify.c | 102 | ||||
-rw-r--r-- | src/recur.c | 328 | ||||
-rw-r--r-- | src/sha1.c | 241 | ||||
-rw-r--r-- | src/sha1.h | 57 | ||||
-rw-r--r-- | src/sigs.c | 4 | ||||
-rw-r--r-- | src/todo.c | 130 | ||||
-rw-r--r-- | src/utf8.c | 344 | ||||
-rw-r--r-- | src/utils.c | 557 | ||||
-rw-r--r-- | src/vars.c | 6 | ||||
-rw-r--r-- | src/wins.c | 135 |
34 files changed, 3511 insertions, 1676 deletions
@@ -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/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..f611079 100644 --- a/doc/calcurse.1.txt +++ b/doc/calcurse.1.txt @@ -103,6 +103,9 @@ 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/*. +*-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. diff --git a/doc/manual.txt b/doc/manual.txt index c0a992d..4964a21 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -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 @@ -210,6 +209,9 @@ 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/`. +`-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. @@ -624,6 +626,9 @@ These options control `calcurse` general behavior, as described below: 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. +`auto_gc` (default: *no*):: + Automatically run the garbage collector for note files when quitting. + `periodic_save` (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 @@ -805,6 +810,10 @@ $ calcurse --next | mail -s "[calcurse] upcoming appointment!" user@host.com ---- ==== +`notify-all` (default: *no*):: + Invert the sense of flagging an appointment as `important`. If this is + enabled, all appointments will be notified - except for flagged ones. + `notify-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 diff --git a/doc/submitting-patches.txt b/doc/submitting-patches.txt new file mode 100644 index 0000000..6fbb5cd --- /dev/null +++ b/doc/submitting-patches.txt @@ -0,0 +1,192 @@ +//// +/* + * Copyright (c) 2004-2011 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/src/Makefile.am b/src/Makefile.am index faacf46..942e7a2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,20 +8,25 @@ calcurse_SOURCES = \ htable.h \ llist.h \ llist_ts.h \ + sha1.h \ apoint.c \ args.c \ calendar.c \ custom.c \ day.c \ event.c \ + getstring.c \ help.c \ io.c \ keys.c \ llist.c \ + note.c \ notify.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..1ca6639 100644 --- a/src/apoint.c +++ b/src/apoint.c @@ -46,21 +46,21 @@ static struct apoint bkp_cut_apoint; static int hilt; void -apoint_free_bkp (enum eraseflg flag) +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); + erase_note (&bkp_cut_apoint.note); } static void apoint_free (struct apoint *apt) { mem_free (apt->mesg); - erase_note (&apt->note, ERASE_FORCE_KEEP_NOTE); + erase_note (&apt->note); mem_free (apt); } @@ -103,28 +103,28 @@ apoint_hilt_set (int highlighted) } void -apoint_hilt_decrease (void) +apoint_hilt_decrease (int n) { - hilt--; + hilt -= n; } void -apoint_hilt_increase (void) +apoint_hilt_increase (int n) { - hilt++; + hilt += n; } /* Return which appointment is highlighted. */ int apoint_hilt (void) { - return (hilt); + return hilt; } 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 * @@ -154,27 +154,28 @@ void apoint_add (void) { #define LTIME 6 +#define LDUR 12 char *mesg_1 = - _("Enter start time ([hh:mm] or [h:mm]), " - "leave blank for an all-day event : "); + _("Enter start time ([hh:mm]), leave blank for an all-day event : "); char *mesg_2 = - _("Enter end time ([hh:mm] or [h:mm]) or duration (in minutes) : "); + _("Enter end time ([hh:mm]) or duration ([+hh:mm]) : "); char *mesg_3 = _("Enter description :"); char *format_message_1 = - _("You entered an invalid start time, should be [h:mm] or [hh:mm]"); + _("You entered an invalid start time, should be [hh:mm]"); char *format_message_2 = - _("You entered an invalid end time, should be [h:mm] or [hh:mm] or [mm]"); + _("You entered an invalid end time, should be [hh:mm], [+hh:mm] or [+mm]"); char *enter_str = _("Press [Enter] to continue"); int Id = 1; char item_time[LTIME] = ""; 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 + for (;;) { status_mesg (mesg_1, ""); if (getstring (win[STA].p, item_time, LTIME, 0, 1) != GETSTRING_ESC) @@ -184,18 +185,18 @@ apoint_add (void) is_appointment = 0; break; } - else if (check_time (item_time) != 1) + + if (parse_time (item_time, &heures, &minutes) == 1) + break; + else { status_mesg (format_message_1, enter_str); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); } - else - (void)sscanf (item_time, "%u:%u", &heures, &minutes); } else return; } - while (check_time (item_time) != 1); /* * Check if an event or appointment is entered, @@ -205,23 +206,16 @@ apoint_add (void) if (is_appointment) { /* Get the appointment duration */ item_time[0] = '\0'; - do + for (;;) { 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 (getstring (win[STA].p, item_time, LDUR, 0, 1) != GETSTRING_ESC) { - if (check_time (item_time) == 2) - apoint_duration = atoi (item_time); - else if (check_time (item_time) == 1) + if (*item_time == '+' && parse_duration (item_time + 1, + &apoint_duration) == 1) + break; + else if (parse_time (item_time, &end_h, &end_m) == 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 @@ -232,10 +226,17 @@ apoint_add (void) apoint_duration = MININSEC - minutes + end_m + (end_h - (heures + 1)) * MININSEC; } + break; + } + else + { + status_mesg (format_message_2, enter_str); + wgetch (win[STA].p); } } + else + return; } - while (check_time (item_time) == 0); } else /* Insert the event Id */ Id = 1; @@ -246,14 +247,12 @@ apoint_add (void) if (is_appointment) { apoint_start = date2sec (*calendar_get_slctd_day (), heures, minutes); - (void)apoint_new (item_mesg, 0L, apoint_start, - min2sec (apoint_duration), 0L); + 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); + event_new (item_mesg, 0L, date2sec (*calendar_get_slctd_day (), 0, 0), Id); if (hilt == 0) hilt++; @@ -384,9 +383,9 @@ apoint_inday (struct apoint *i, long start) { if (i->start <= start + DAYINSEC && i->start + i->dur > start) { - return (1); + return 1; } - return (0); + return 0; } void @@ -395,21 +394,21 @@ apoint_sec2str (struct apoint *o, int type, long day, char *start, char *end) struct tm *lt; time_t t; - if (o->start < day && type == APPT) - (void)strncpy (start, "..:..", 6); + if (o->start < day) + strncpy (start, "..:..", 6); else { t = o->start; lt = localtime (&t); - (void)snprintf (start, HRMIN_SIZE, "%02u:%02u", lt->tm_hour, lt->tm_min); + 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); + if (o->start + o->dur > day + DAYINSEC) + 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); + snprintf (end, HRMIN_SIZE, "%02u:%02u", lt->tm_hour, lt->tm_min); } } @@ -421,25 +420,23 @@ apoint_write (struct apoint *o, FILE *f) 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); + 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); + 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 * @@ -449,10 +446,10 @@ apoint_scan (FILE *f, struct tm start, struct tm end, char state, char *note) time_t tstart, tend, t; t = time (NULL); - (void)localtime (&t); + localtime (&t); /* Read the appointment description */ - (void)fgets (buf, sizeof buf, f); + fgets (buf, sizeof buf, f); newline = strchr (buf, '\n'); if (newline) *newline = '\0'; @@ -468,7 +465,7 @@ apoint_scan (FILE *f, struct tm start, struct tm end, char state, char *note) tend = mktime (&end); EXIT_IF (tstart == -1 || tend == -1 || tstart > tend, _("date error in appointment")); - return (apoint_new (buf, note, tstart, tend - tstart, state)); + return apoint_new (buf, note, tstart, tend - tstart, state); } /* Retrieve an appointment from the list, given the day and item position. */ @@ -500,20 +497,18 @@ apoint_delete_bynum (long start, unsigned num, enum eraseflg flag) switch (flag) { case ERASE_FORCE_ONLY_NOTE: - erase_note (&apt->note, flag); + erase_note (&apt->note); break; case ERASE_CUT: - apoint_free_bkp (ERASE_FORCE); + apoint_free_bkp (); apoint_dup (apt, &bkp_cut_apoint); - erase_note (&apt->note, ERASE_FORCE_KEEP_NOTE); + 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); - 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); @@ -581,7 +576,7 @@ apoint_scroll_pad_up (int nb_events_inday) static int apoint_starts_after (struct apoint *apt, long time) { - return (apt->start > time); + return apt->start > time; } /* @@ -611,7 +606,7 @@ apoint_check_next (struct notify_app *app, long start) LLIST_TS_UNLOCK (&alist_p); - return (app); + return app; } /* @@ -627,7 +622,7 @@ apoint_recur_s2apoint_s (struct recur_apoint *p) a->mesg = mem_strdup (p->mesg); a->start = p->start; a->dur = p->dur; - return (a); + return a; } /* @@ -686,7 +681,7 @@ apoint_update_panel (int which_pan) if (slctd_date.dd < 10) title_xpos++; date = date2sec (slctd_date, 0, 0); - day_write_pad (date, app_width, app_length, hilt); + 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, @@ -726,12 +721,11 @@ apoint_paste_item (void) 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); + 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); - apoint_free_bkp (ERASE_FORCE_KEEP_NOTE); + apoint_free_bkp (); } @@ -51,8 +51,8 @@ static void usage () { - char *arg_usage = - _("Usage: calcurse [-h|-v] [-N] [-an] [-t[num]] [-i<file>] [-x[format]]\n" + const char *arg_usage = + _("Usage: calcurse [-g|-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); @@ -61,7 +61,7 @@ usage () static void usage_try () { - char *arg_usage_try = _("Try 'calcurse -h' for more information.\n"); + const char *arg_usage_try = _("Try 'calcurse -h' for more information.\n"); fputs (arg_usage_try, stdout); } @@ -71,14 +71,11 @@ usage_try () static void version_arg () { - char vtitle[BUFSIZ]; - char *vtext = + const char *vtext = _("\nCopyright (c) 2004-2011 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); + fprintf (stdout, _("Calcurse %s - text-based organizer\n"), VERSION); fputs (vtext, stdout); } @@ -88,8 +85,7 @@ version_arg () static void help_arg () { - char htitle[BUFSIZ]; - char *htext = + const char *htext = _("\nMiscellaneous:\n" " -h, --help\n" " print this help and exit.\n" @@ -110,6 +106,8 @@ help_arg () " 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" @@ -146,9 +144,7 @@ help_arg () "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); + fprintf (stdout, _("Calcurse %s - text-based organizer\n"), VERSION); usage (); fputs (htext, stdout); } @@ -183,7 +179,7 @@ status_arg (void) else if (dpid) fprintf (stdout, _("calcurse is running in background (pid %d)\n"), dpid); else - fprintf (stdout, _("calcurse is not running\n")); + puts (_("calcurse is not running\n")); } /* @@ -213,7 +209,7 @@ print_notefile (FILE *out, char *filename, int nbtab) else linestarter[0] = '\0'; - (void)snprintf (path_to_notefile, BUFSIZ, "%s/%s", path_notes, filename); + snprintf (path_to_notefile, BUFSIZ, "%s/%s", path_notes, filename); notefile = fopen (path_to_notefile, "r"); if (notefile) { @@ -323,8 +319,8 @@ next_arg (void) 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); + snprintf (mesg, BUFSIZ, " [%02d:%02d] %s\n", hours_left, min_left, + next_app.txt); fputs (mesg, stdout); mem_free (next_app.txt); } @@ -398,7 +394,7 @@ app_arg (int add_line, struct date *day, long date, int print_note, print_notefile (stdout, re->note, 2); } - LLIST_FIND_FOREACH (&eventlist, today, event_inday, i) + 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) @@ -436,6 +432,7 @@ app_arg (int add_line, struct date *day, long date, int print_note, { 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) { @@ -451,7 +448,8 @@ app_arg (int add_line, struct date *day, long date, int print_note, if (apt && ra) { - if (apt->start <= recur_apoint_inday (ra, today)) + if (recur_apoint_find_occurrence (ra, today, &occurrence) && + apt->start <= occurrence) ra = NULL; else apt = NULL; @@ -517,7 +515,7 @@ app_arg (int add_line, struct date *day, long date, int print_note, LLIST_TS_UNLOCK (&recur_alist_p); LLIST_TS_UNLOCK (&alist_p); - return (app_found); + return app_found; } static void @@ -550,7 +548,7 @@ display_app (struct tm *t, int numdays, int add_line, int print_note, if (app_found) add_line = 1; t->tm_mday++; - (void)mktime (t); + mktime (t); } } @@ -598,15 +596,15 @@ date_arg (char *ddate, int add_line, int print_note, struct conf *conf, 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); + 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)); + snprintf (outstr, BUFSIZ, + "Possible argument format are: '%s' or 'n'\n", + DATEFMT_DESC (conf->input_datefmt)); fputs (_(outstr), stdout); more_info (); } @@ -652,7 +650,7 @@ date_arg_extended (char *startday, char *range, int add_line, int print_note, { t.tm_year -= 1900; t.tm_mon--; - (void)mktime (&t); + mktime (&t); } else { @@ -667,9 +665,9 @@ date_arg_extended (char *startday, char *range, int add_line, int print_note, { 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)); + 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 (); @@ -692,6 +690,7 @@ parse_args (int argc, char **argv, struct conf *conf) 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 Nflag = 0; /* -N: also print note content with apps and todos */ @@ -714,13 +713,14 @@ parse_args (int argc, char **argv, struct conf *conf) STATUS_OPT = CHAR_MAX + 1 }; - static char *optstr = "hvnNax::t::d:c:r::s::S:D:i:"; + static 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'}, @@ -766,6 +766,9 @@ parse_args (int argc, char **argv, struct conf *conf) case 'h': hflag = 1; break; + case 'g': + gflag = 1; + break; case 'i': iflag = 1; multiple_flag++; @@ -812,7 +815,7 @@ parse_args (int argc, char **argv, struct conf *conf) { usage (); usage_try (); - return (EXIT_FAILURE); + return EXIT_FAILURE; } } else @@ -900,18 +903,30 @@ parse_args (int argc, char **argv, struct conf *conf) 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, (int *)0); - io_check_dir (path_notes, (int *)0); + io_check_dir (path_dir, NULL); + io_check_dir (path_notes, NULL); } if (iflag) { - io_check_file (path_apts, (int *)0); - io_check_file (path_todo, (int *)0); + 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 (conf); io_load_app (); @@ -923,8 +938,8 @@ parse_args (int argc, char **argv, struct conf *conf) } if (xflag) { - io_check_file (path_apts, (int *)0); - io_check_file (path_todo, (int *)0); + io_check_file (path_apts, NULL); + io_check_file (path_todo, NULL); io_load_app (); io_load_todo (); io_export_data (xfmt, conf); @@ -933,24 +948,24 @@ parse_args (int argc, char **argv, struct conf *conf) } if (tflag) { - io_check_file (path_todo, (int *)0); + io_check_file (path_todo, NULL); io_load_todo (); todo_arg (tnum, Nflag, preg); non_interactive = 1; } if (nflag) { - io_check_file (path_apts, (int *)0); + io_check_file (path_apts, NULL); 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_check_file (path_apts, NULL); + io_check_file (path_conf, NULL); io_load_app (); - custom_load_conf (conf, 0); /* To get output date format. */ + custom_load_conf (conf); /* To get output date format. */ if (dflag) date_arg (ddate, add_line, Nflag, conf, preg); if (rflag || sflag) @@ -962,13 +977,13 @@ parse_args (int argc, char **argv, struct conf *conf) { struct date day; - io_check_file (path_apts, (int *)0); - io_check_file (path_conf, (int *)0); + io_check_file (path_apts, NULL); + io_check_file (path_conf, NULL); vars_init (conf); - custom_load_conf (conf, 0); /* To get output date format. */ + custom_load_conf (conf); /* 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); + app_arg (add_line, &day, 0, Nflag, conf, preg); non_interactive = 1; } } diff --git a/src/calcurse.c b/src/calcurse.c index 662f185..cde2005 100644 --- a/src/calcurse.c +++ b/src/calcurse.c @@ -39,6 +39,22 @@ #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, @@ -50,20 +66,15 @@ 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, ""); @@ -148,7 +159,7 @@ main (int argc, char **argv) * configuration (the display is then updated), and then * the todo list, appointments and events. */ - custom_load_conf (&conf, background); + custom_load_conf (&conf); wins_erase_status_bar (); io_load_keys (conf.pager); io_load_todo (); @@ -156,11 +167,11 @@ main (int argc, char **argv) wins_reinit (); if (notify_bar ()) notify_start_main_thread (); - wins_update (); + wins_update (FLAG_ALL); io_startup_screen (conf.skip_system_dialogs, no_data_file); - inday = *day_process_storage (0, day_changed, &inday); + inday = *day_process_storage (0, 0, &inday); wins_slctd_set (CAL); - wins_update (); + wins_update (FLAG_ALL); calendar_start_date_thread (); if (conf.periodic_save > 0) io_start_psave_thread (&conf); @@ -170,59 +181,44 @@ main (int argc, char **argv) { int key; - do_update = 1; - key = keys_getch (win[STA].p); - switch (key) + if (resize) { - case ERR: - do_update = 0; - break; + resize = 0; + wins_reset (); + } + 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 (); - /* 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)) + if ((todo_hilt () == 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)) + if ((apoint_hilt () == 0) && + ((inday.nb_events + inday.nb_apoints) > 0)) apoint_hilt_set (1); - else - apoint_hilt_set (sav_hilt_app); 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: @@ -233,8 +229,8 @@ main (int argc, char **argv) calendar_goto_today (); else calendar_change_day (conf.input_datefmt); - do_storage = 1; - day_changed = 1; + inday = do_storage (1); + wins_update (FLAG_CAL | FLAG_APP | FLAG_STA); break; case KEY_VIEW_ITEM: @@ -242,6 +238,7 @@ main (int argc, char **argv) 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: @@ -283,25 +280,29 @@ main (int argc, char **argv) case 'S': custom_sidebar_config (); break; + default: + continue; } wins_reset (); - wins_update (); - do_storage = 1; + wins_update (FLAG_ALL); wins_erase_status_bar (); custom_config_bar (); + inday = do_storage (0); } - wins_update (); + wins_update (FLAG_ALL); break; case KEY_GENERIC_ADD_APPT: apoint_add (); - do_storage = 1; + 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 (); + todo_hilt_increase (1); + wins_update (FLAG_TOD | FLAG_STA); break; case KEY_ADD_ITEM: @@ -309,12 +310,14 @@ main (int argc, char **argv) { case APP: apoint_add (); - do_storage = 1; + 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 (); + todo_hilt_increase (1); + wins_update (FLAG_TOD | FLAG_STA); break; default: break; @@ -323,25 +326,38 @@ main (int argc, char **argv) case KEY_EDIT_ITEM: if (wins_slctd () == APP && apoint_hilt () != 0) - day_edit_item (&conf); + { + day_edit_item (&conf); + inday = do_storage (0); + wins_update (FLAG_CAL | FLAG_APP | FLAG_STA); + } else if (wins_slctd () == TOD && todo_hilt () != 0) - todo_edit_item (); - do_storage = 1; + { + todo_edit_item (); + wins_update (FLAG_TOD | FLAG_STA); + } break; case KEY_DEL_ITEM: if (wins_slctd () == APP && apoint_hilt () != 0) - apoint_delete (&conf, &inday.nb_events, &inday.nb_apoints); + { + apoint_delete (&conf, &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 (&conf); - do_storage = 1; + { + todo_delete (&conf); + 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); - do_storage = 1; + inday = do_storage (0); + wins_update (FLAG_CAL | FLAG_APP); } break; @@ -350,22 +366,38 @@ main (int argc, char **argv) { apoint_paste (&inday.nb_events, &inday.nb_apoints, cut_item); cut_item = 0; - do_storage = 1; + 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 (&conf); - do_storage = 1; + 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 (); + { + 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 (&conf); else if (wins_slctd () == TOD && todo_hilt () != 0) - todo_flag (); - do_storage = 1; + todo_pipe_item (); + wins_update (FLAG_ALL); break; case KEY_RAISE_PRIORITY: @@ -377,15 +409,19 @@ main (int argc, char **argv) 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); + { + day_edit_note (conf.editor); + inday = do_storage (0); + } else if (wins_slctd () == TOD && todo_hilt () != 0) todo_edit_note (conf.editor); - do_storage = 1; + wins_update (FLAG_ALL); break; case KEY_VIEW_NOTE: @@ -393,21 +429,25 @@ main (int argc, char **argv) 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 (&conf, IO_SAVE_DISPLAY_BAR); + wins_update (FLAG_STA); break; case KEY_GENERIC_IMPORT: wins_erase_status_bar (); io_import_data (IO_IMPORT_ICAL, &conf, NULL); - do_storage = 1; + inday = do_storage (0); + wins_update (FLAG_ALL); break; case KEY_GENERIC_EXPORT: @@ -427,21 +467,21 @@ main (int argc, char **argv) break; } wins_reset (); - wins_update (); - do_storage = 1; + wins_update (FLAG_ALL); wins_erase_status_bar (); io_export_bar (); } - wins_update (); + 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) { - do_storage = 1; - day_changed = 1; - calendar_move (RIGHT); + calendar_move (RIGHT, count); + inday = do_storage (1); + wins_update (FLAG_CAL | FLAG_APP); } break; @@ -449,9 +489,9 @@ main (int argc, char **argv) case KEY_MOVE_LEFT: if (wins_slctd () == CAL || key == KEY_GENERIC_PREV_DAY) { - do_storage = 1; - day_changed = 1; - calendar_move (LEFT); + calendar_move (LEFT, count); + inday = do_storage (1); + wins_update (FLAG_CAL | FLAG_APP); } break; @@ -459,20 +499,26 @@ main (int argc, char **argv) case KEY_MOVE_UP: if (wins_slctd () == CAL || key == KEY_GENERIC_PREV_WEEK) { - do_storage = 1; - day_changed = 1; - calendar_move (UP); + calendar_move (UP, count); + inday = do_storage (1); + wins_update (FLAG_CAL | FLAG_APP); } - else if ((wins_slctd () == APP) && (apoint_hilt () > 1)) + else if (wins_slctd () == APP) { - apoint_hilt_decrease (); + 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) && (todo_hilt () > 1)) + else if (wins_slctd () == TOD) { - todo_hilt_decrease (); + if (count >= todo_hilt ()) + count = todo_hilt () - 1; + todo_hilt_decrease (count); if (todo_hilt_pos () < 0) - todo_first_decrease (); + todo_first_increase (todo_hilt_pos ()); + wins_update (FLAG_TOD); } break; @@ -480,55 +526,68 @@ main (int argc, char **argv) case KEY_MOVE_DOWN: if (wins_slctd () == CAL || key == KEY_GENERIC_NEXT_WEEK) { - do_storage = 1; - day_changed = 1; - calendar_move (DOWN); + calendar_move (DOWN, count); + inday = do_storage (1); + wins_update (FLAG_CAL | FLAG_APP); } - else if ((wins_slctd () == APP) && - (apoint_hilt () < inday.nb_events + inday.nb_apoints)) + else if (wins_slctd () == APP) { - apoint_hilt_increase (); + 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) && (todo_hilt () < todo_nb ())) + else if (wins_slctd () == TOD) { - todo_hilt_increase (); - if (todo_hilt_pos () == win[TOD].h - 4) - todo_first_increase (); + 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) { - do_storage = 1; - day_changed = 1; - calendar_move (WEEK_START); + 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) { - do_storage = 1; - day_changed = 1; - calendar_move (WEEK_END); + 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 (); + { + calendar_view_prev (); + wins_update (FLAG_CAL | FLAG_APP); + } break; case KEY_GENERIC_SCROLL_DOWN: if (wins_slctd () == CAL) - calendar_view_next (); + { + calendar_view_next (); + wins_update (FLAG_CAL | FLAG_APP); + } break; case KEY_GENERIC_QUIT: if (conf.auto_save) io_save_cal (&conf, IO_SAVE_DISPLAY_BAR); + if (conf.auto_gc) + note_gc (); if (conf.confirm_quit) { @@ -539,6 +598,7 @@ main (int argc, char **argv) else { wins_erase_status_bar (); + wins_update (FLAG_STA); break; } } @@ -546,34 +606,15 @@ main (int argc, char **argv) exit_calcurse (EXIT_SUCCESS); break; + case KEY_RESIZE: + case ERR: + /* Do not reset the count parameter on resize or error. */ + continue; + default: - do_update = 0; 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); - } - } - - if (resize) - { - resize = 0; - do_update = 0; - wins_reset (); - } - - if (do_update) - wins_update (); + count = 0; } } diff --git a/src/calcurse.h b/src/calcurse.h index 091d16a..adb2c1e 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -103,99 +103,111 @@ #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 STATUSHEIGHT 2 -#define NOTESIZ 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 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} @@ -203,12 +215,22 @@ #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 auto_gc; unsigned periodic_save; unsigned confirm_quit; unsigned confirm_delete; @@ -217,7 +239,7 @@ struct conf { char *editor; char *pager; char output_datefmt[BUFSIZ]; /* format for displaying date */ - int input_datefmt; /* format for reading date */ + int input_datefmt; /* format for reading date */ }; /* Daemon-related configuration. */ @@ -239,16 +261,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; @@ -263,8 +282,8 @@ struct apoint 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 */ +#define APOINT_NOTIFY 0x1 /* Item needs to be notified */ +#define APOINT_NOTIFIED 0x2 /* Item was already notified */ int state; char *mesg; @@ -395,6 +414,7 @@ enum key { KEY_DEL_ITEM, KEY_EDIT_ITEM, KEY_VIEW_ITEM, + KEY_PIPE_ITEM, KEY_FLAG_ITEM, KEY_REPEAT_ITEM, KEY_EDIT_NOTE, @@ -421,6 +441,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, @@ -455,13 +482,14 @@ struct pad { /* 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 */ + 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 */ - char *shell; /* user shell to launch notif. cmd */ + char cmd[BUFSIZ]; /* notification command */ + char *shell; /* user shell to launch notif. cmd */ + unsigned notify_all; /* notify all appointments */ pthread_mutex_t mutex; }; @@ -478,7 +506,6 @@ enum item_type { enum eraseflg { ERASE_DONT_FORCE, ERASE_FORCE, - ERASE_FORCE_KEEP_NOTE, ERASE_FORCE_ONLY_NOTE, ERASE_CUT }; @@ -548,12 +575,12 @@ enum save_display { /* apoint.c */ extern llist_ts_t alist_p; -void apoint_free_bkp (enum eraseflg); +void apoint_free_bkp (void); 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); +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); @@ -595,7 +622,7 @@ 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); +void calendar_move (enum move, int); long calendar_start_of_year (void); long calendar_end_of_year (void); char *calendar_get_pom (time_t); @@ -604,7 +631,7 @@ char *calendar_get_pom (time_t); 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_load_conf (struct conf *); void custom_config_bar (void); void custom_layout_config (void); void custom_sidebar_config (void); @@ -631,6 +658,7 @@ 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_pipe_item (struct conf *); /* dmon.c */ void dmon_start (int); @@ -638,7 +666,7 @@ void dmon_stop (void); /* event.c */ extern llist_t eventlist; -void event_free_bkp (enum eraseflg); +void event_free_bkp (void); void event_llist_init (void); void event_llist_free (void); struct event *event_new (char *, char *, long, int); @@ -653,6 +681,10 @@ void event_paste_item (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); + /* io.c */ unsigned io_fprintln (const char *, const char *, ...); void io_init (char *, char *); @@ -683,6 +715,7 @@ 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); @@ -690,7 +723,7 @@ 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); +enum key keys_getch (WINDOW *win, int *); int keys_assign_binding (int, enum key); void keys_remove_binding (int, enum key); int keys_str2int (char *); @@ -738,6 +771,13 @@ void mem_stats (void); #endif /* CALCURSE_MEMORY_DEBUG */ +/* note.c */ +void edit_note (char **, char *); +void view_note (char *, 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); @@ -764,8 +804,8 @@ void notify_config_bar (void); /* 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_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); @@ -781,8 +821,17 @@ struct recur_apoint *recur_apoint_scan (FILE *, struct tm, struct tm, 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_inday (long, llist_t *, int, int, long, long); +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, @@ -805,18 +854,19 @@ 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); +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 (void); -void todo_first_decrease (void); +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 (struct conf *); void todo_chg_priority (int); @@ -824,9 +874,14 @@ void todo_edit_item (void); void todo_update_panel (int); void todo_edit_note (char *); void todo_view_note (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); @@ -836,8 +891,6 @@ 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); @@ -849,7 +902,6 @@ 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); @@ -859,17 +911,23 @@ 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 *, +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 *, char *const *); +int shell_exec (int *, int *, char *); +int child_wait (int *, int *, int); +void press_any_key (void); /* vars.c */ extern int col, row; extern int resize; extern unsigned colorize; +extern int foreground, background; extern enum ui_mode ui_mode; extern int days[12]; extern char *monthnames[12]; @@ -914,11 +972,13 @@ 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_update_border (int); +void wins_update_panels (int); +void wins_update (int); void wins_reset (void); -void wins_launch_external (const char *, const char *); +void wins_prepare_external (void); +void wins_unprepare_external (void); +void wins_launch_external (char *, char *); void wins_status_bar (void); void wins_erase_status_bar (void); void wins_other_status_page (int); diff --git a/src/calendar.c b/src/calendar.c index e303ab9..8fea79d 100644 --- a/src/calendar.c +++ b/src/calendar.c @@ -124,13 +124,13 @@ calendar_date_thread (void *arg) tomorrow = (time_t) (get_today () + DAYINSEC); while ((actual = time (NULL)) < tomorrow) - (void)sleep (tomorrow - actual); + sleep (tomorrow - actual); calendar_set_current_date (); calendar_update_panel (&win[CAL]); } - return (void *)0; + return NULL; } /* Launch the calendar date thread. */ @@ -198,7 +198,7 @@ calendar_change_first_day_of_week (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. */ @@ -221,14 +221,14 @@ calendar_init_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) { - return (date2sec (slctd_day, 0, 0)); + return date2sec (slctd_day, 0, 0); } static int @@ -236,12 +236,12 @@ 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; } @@ -249,14 +249,14 @@ calendar_get_wday (struct date *date) static unsigned months_to_days (unsigned month) { - return ((month * 3057 - 3007) / 100); + return (month * 3057 - 3007) / 100; } 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 @@ -270,7 +270,7 @@ ymd_to_scalar (unsigned year, unsigned month, unsigned day) year--; scalar += years_to_days (year); - return (scalar); + return scalar; } /* @@ -287,11 +287,11 @@ date_change (struct tm *date, int delta_month, int delta_day) t.tm_mday += delta_day; if (mktime (&t) == -1) - return (1); + return 1; else { *date = t; - return (0); + return 0; } } @@ -495,12 +495,12 @@ draw_weekly_view (struct window *cwin, struct date *current_day, 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); @@ -572,7 +572,7 @@ draw_weekly_view (struct window *cwin, struct date *current_day, } /* get next day */ - (void)date_change (&t, 0, 1); + date_change (&t, 0, 1); } /* Draw marks to indicate midday on the sides of the calendar. */ @@ -636,7 +636,7 @@ calendar_change_day (int datefmt) while (wrong_day) { - (void)snprintf (outstr, BUFSIZ, request_date, DATEFMT_DESC (datefmt)); + snprintf (outstr, BUFSIZ, request_date, DATEFMT_DESC (datefmt)); status_mesg (_(outstr), ""); if (getstring (win[STA].p, selected_day, LDAY, 0, 1) == GETSTRING_ESC) return; @@ -659,7 +659,7 @@ calendar_change_day (int datefmt) if (wrong_day) { status_mesg (mesg_line1, mesg_line2); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); } } } @@ -668,12 +668,12 @@ calendar_change_day (int datefmt) } void -calendar_move (enum move move) +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; @@ -684,42 +684,44 @@ calendar_move (enum move move) if ((slctd_day.dd <= 7) && (slctd_day.mm == 1) && (slctd_day.yyyy == 1902)) return; - ret = date_change (&t, 0, -WEEKINDAYS); + ret = date_change (&t, 0, -count * 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); + ret = date_change (&t, 0, count * WEEKINDAYS); break; case LEFT: if ((slctd_day.dd == 1) && (slctd_day.mm == 1) && (slctd_day.yyyy == 1902)) return; - ret = date_change (&t, 0, -1); + ret = date_change (&t, 0, -count); break; case RIGHT: if ((slctd_day.dd == 31) && (slctd_day.mm == 12) && (slctd_day.yyyy == 2037)) return; - ret = date_change (&t, 0, 1); + ret = date_change (&t, 0, count); break; case WEEK_START: /* Normalize struct tm to get week day number. */ - (void)mktime (&t); + 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); + days_to_remove += (count - 1) * WEEKINDAYS; + ret = date_change (&t, 0, -days_to_remove); break; case WEEK_END: - (void)mktime (&t); + 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: @@ -816,7 +818,7 @@ calendar_end_of_year (void) static double dtor (double deg) { - return (deg * M_PI / 180); + return deg * M_PI / 180; } /* @@ -868,7 +870,7 @@ potm (double days) 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 */ + return 50.0 * (1 - cos (dtor (D))); /* sec 67 #3 */ } /* @@ -898,7 +900,7 @@ pom (time_t tmpt) for (cnt = GMT->tm_year; cnt < EPOCH; ++cnt) days -= ISLEAP (cnt + TM_YEAR_BASE) ? 366 : 365; - return (potm (days)); + return potm (days); } /* @@ -926,5 +928,5 @@ calendar_get_pom (time_t date) && 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/custom.c b/src/custom.c index 1f75978..5700640 100644 --- a/src/custom.c +++ b/src/custom.c @@ -37,13 +37,14 @@ #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_AUTOGC, CUSTOM_CONF_PERIODICSAVE, CUSTOM_CONF_CONFIRMQUIT, CUSTOM_CONF_CONFIRMDELETE, @@ -59,11 +60,43 @@ enum conf_var { CUSTOM_CONF_NOTIFYBARCLOCK, CUSTOM_CONF_NOTIFYBARWARNING, CUSTOM_CONF_NOTIFYBARCOMMAND, + CUSTOM_CONF_NOTIFYALL, CUSTOM_CONF_OUTPUTDATEFMT, CUSTOM_CONF_INPUTDATEFMT, CUSTOM_CONF_DMON_ENABLE, CUSTOM_CONF_DMON_LOG, - CUSTOM_CONF_VARIABLES + CUSTOM_CONF_INVALID +}; + +struct conf_varname { + enum conf_var var; + const char *name; +}; + +static struct conf_varname conf_varmap[] = +{ + { CUSTOM_CONF_AUTOSAVE, "auto_save" }, + { CUSTOM_CONF_AUTOGC, "auto_gc" }, + { CUSTOM_CONF_PERIODICSAVE, "periodic_save" }, + { CUSTOM_CONF_CONFIRMQUIT, "confirm_quit" }, + { CUSTOM_CONF_CONFIRMDELETE, "confirm_delete" }, + { CUSTOM_CONF_SKIPSYSTEMDIALOGS, "skip_system_dialogs" }, + { CUSTOM_CONF_SKIPPROGRESSBAR, "skip_progress_bar" }, + { CUSTOM_CONF_CALENDAR_DEFAULTVIEW, "calendar_default_view" }, + { CUSTOM_CONF_WEEKBEGINSONMONDAY, "week_begins_on_monday" }, + { CUSTOM_CONF_COLORTHEME, "color-theme" }, + { CUSTOM_CONF_LAYOUT, "layout" }, + { CUSTOM_CONF_SBAR_WIDTH, "side-bar_width" }, + { CUSTOM_CONF_NOTIFYBARSHOW, "notify-bar_show" }, + { CUSTOM_CONF_NOTIFYBARDATE, "notify-bar_date" }, + { CUSTOM_CONF_NOTIFYBARCLOCK, "notify-bar_clock" }, + { CUSTOM_CONF_NOTIFYBARWARNING, "notify-bar_warning" }, + { CUSTOM_CONF_NOTIFYBARCOMMAND, "notify-bar_command" }, + { CUSTOM_CONF_NOTIFYALL, "notify-all" }, + { CUSTOM_CONF_OUTPUTDATEFMT, "output_datefmt" }, + { CUSTOM_CONF_INPUTDATEFMT, "input_datefmt" }, + { CUSTOM_CONF_DMON_ENABLE, "notify-daemon_enable" }, + { CUSTOM_CONF_DMON_LOG, "notify-daemon_log" } }; struct attribute { @@ -73,18 +106,39 @@ struct attribute { static struct attribute attr; -static unsigned -fill_config_var (char *string) +static int +conf_parse_bool (unsigned *dest, char *val) { - if (strncmp (string, "yes", 3) == 0) - return 1; - else if (strncmp (string, "no", 2) == 0) + if (strncmp (val, "yes", 4) == 0) + *dest = 1; + else if (strncmp (val, "no", 3) == 0) + *dest = 0; + else return 0; + + return 1; +} + +static int +conf_parse_unsigned (unsigned *dest, char *val) +{ + if (is_all_digit (val)) + *dest = atoi (val); else - { - EXIT (_("wrong configuration variable format.")); - return 0; - } + return 0; + + return 1; +} + +static int +conf_parse_int (int *dest, char *val) +{ + if ((*val == '+' || *val == '-' || isdigit (*val)) && is_all_digit (val + 1)) + *dest = atoi (val); + else + return 0; + + return 1; } /* @@ -92,8 +146,8 @@ fill_config_var (char *string) * 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) +static int +conf_parse_color (char *val) { #define AWAITED_COLORS 2 @@ -101,15 +155,12 @@ custom_load_color (char *color, int background) char c[AWAITED_COLORS][BUFSIZ]; int colr[AWAITED_COLORS]; - len = strlen (color); + len = strlen (val); 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 */ - } + if (sscanf (val, "%s on %s", c[0], c[1]) != AWAITED_COLORS) + return 0; for (i = 0; i < AWAITED_COLORS; i++) { @@ -132,17 +183,17 @@ custom_load_color (char *color, int background) else if (!strncmp (c[i], "default", 7)) colr[i] = background; else - { - EXIT (_("wrong color name")); - /* NOTREACHED */ - } + return 0; } init_pair (COLR_CUSTOM, colr[0], colr[1]); } - else if (len > 0 && len < 2) + else if (len == 1) { /* Old version configuration */ - color_num = atoi (color); + if (isdigit (*val)) + color_num = atoi (val); + else + return 0; switch (color_num) { @@ -174,15 +225,13 @@ custom_load_color (char *color, int background) init_pair (COLR_CUSTOM, COLOR_RED, COLR_BLUE); break; default: - EXIT (_("wrong color number")); - /* NOTREACHED */ + return 0; } } else - { - EXIT (_("wrong configuration variable format")); - /* NOTREACHED */ - } + return 0; + + return 1; } /* @@ -233,15 +282,107 @@ custom_remove_attr (WINDOW *win, int attr_num) wattroff (win, attr.nocolor[attr_num]); } +/* Set a configuration variable. */ +static int +custom_set_conf (struct conf *conf, enum conf_var var, char *val) +{ + unsigned tmp; + + switch (var) + { + case CUSTOM_CONF_AUTOSAVE: + return conf_parse_bool (&conf->auto_save, val); + break; + case CUSTOM_CONF_AUTOGC: + return conf_parse_bool (&conf->auto_gc, val); + break; + case CUSTOM_CONF_PERIODICSAVE: + return conf_parse_unsigned (&conf->periodic_save, val); + break; + case CUSTOM_CONF_CONFIRMQUIT: + return conf_parse_bool (&conf->confirm_quit, val); + break; + case CUSTOM_CONF_CONFIRMDELETE: + return conf_parse_bool (&conf->confirm_delete, val); + break; + case CUSTOM_CONF_SKIPSYSTEMDIALOGS: + return conf_parse_bool (&conf->skip_system_dialogs, val); + break; + case CUSTOM_CONF_SKIPPROGRESSBAR: + return conf_parse_bool (&conf->skip_progress_bar, val); + break; + case CUSTOM_CONF_CALENDAR_DEFAULTVIEW: + calendar_set_view (atoi (val)); + break; + case CUSTOM_CONF_WEEKBEGINSONMONDAY: + return conf_parse_bool (&tmp, val); + if (tmp) + calendar_set_first_day_of_week (MONDAY); + else + calendar_set_first_day_of_week (SUNDAY); + break; + case CUSTOM_CONF_COLORTHEME: + return conf_parse_color (val); + break; + case CUSTOM_CONF_LAYOUT: + wins_set_layout (atoi (val)); + break; + case CUSTOM_CONF_SBAR_WIDTH: + wins_set_sbar_width (atoi (val)); + break; + case CUSTOM_CONF_NOTIFYBARSHOW: + return conf_parse_bool (&nbar.show, val); + break; + case CUSTOM_CONF_NOTIFYBARDATE: + strncpy (nbar.datefmt, val, strlen (val) + 1); + break; + case CUSTOM_CONF_NOTIFYBARCLOCK: + strncpy (nbar.timefmt, val, strlen (val) + 1); + break; + case CUSTOM_CONF_NOTIFYBARWARNING: + return conf_parse_int (&nbar.cntdwn, val); + break; + case CUSTOM_CONF_NOTIFYBARCOMMAND: + strncpy (nbar.cmd, val, strlen (val) + 1); + break; + case CUSTOM_CONF_NOTIFYALL: + return conf_parse_bool(&nbar.notify_all, val); + break; + case CUSTOM_CONF_OUTPUTDATEFMT: + if (val[0] != '\0') + strncpy (conf->output_datefmt, val, strlen (val) + 1); + break; + case CUSTOM_CONF_INPUTDATEFMT: + return conf_parse_int (&conf->input_datefmt, val); + if (conf->input_datefmt <= 0 || conf->input_datefmt >= DATE_FORMATS) + conf->input_datefmt = 1; + break; + case CUSTOM_CONF_DMON_ENABLE: + return conf_parse_bool (&dmon.enable, val); + break; + case CUSTOM_CONF_DMON_LOG: + return conf_parse_bool (&dmon.log, val); + break; + default: + return 0; + break; + } + + return 1; +} + /* Load the user configuration. */ void -custom_load_conf (struct conf *conf, int background) +custom_load_conf (struct conf *conf) { FILE *data_file; char *mesg_line1 = _("Failed to open config file"); char *mesg_line2 = _("Press [ENTER] to continue"); char buf[BUFSIZ], e_conf[BUFSIZ]; + int i; + char *name; enum conf_var var; + char *val; data_file = fopen (path_conf, "r"); if (data_file == NULL) @@ -249,156 +390,57 @@ custom_load_conf (struct conf *conf, int background) status_mesg (mesg_line1, mesg_line2); wnoutrefresh (win[STA].p); wins_doupdate (); - (void)keys_getch (win[STA].p); + keys_getch (win[STA].p, NULL); } - 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); + + if (*e_conf == '\0') + continue; + + name = e_conf; + val = strchr (e_conf, '='); + if (val) { - break; + *val = '\0'; + val++; } - io_extract_data (e_conf, buf, sizeof buf); - switch (var) + var = CUSTOM_CONF_INVALID; + for (i = 0; i < sizeof (conf_varmap) / sizeof (struct conf_varname); i++) { - 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")); + if (strncmp (name, conf_varmap[i].name, BUFSIZ) == 0) + { + var = conf_varmap[i].var; + break; + } + } + + if (var == CUSTOM_CONF_INVALID) + { + EXIT (_("configuration variable unknown: \"%s\""), name); /* 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; + if (val && (*val == '\0' || *val == '\n')) + { + /* Backward compatibility mode. */ + if (fgets (buf, sizeof buf, data_file) == NULL) + break; + io_extract_data (e_conf, buf, sizeof buf); + val = e_conf; + } + + if (!val || !custom_set_conf (conf, var, val)) + { + EXIT (_("wrong configuration variable format for \"%s\""), name); + /* NOTREACHED */ + } } file_close (data_file, __FILE_POS__); pthread_mutex_unlock (&nbar.mutex); @@ -530,14 +572,14 @@ custom_layout_config (void) " 'a' -> appointment panel\n\n" " 't' -> todo panel\n\n"); - conf_win.p = (WINDOW *)0; - (void)snprintf (label, BUFSIZ, _("layout configuration")); + conf_win.p = NULL; + strncpy (label, _("layout configuration"), BUFSIZ); 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) + while ((ch = keys_getch (win[STA].p, NULL)) != KEY_GENERIC_QUIT) { need_reset = 0; switch (ch) @@ -621,7 +663,7 @@ custom_sidebar_config (void) keys_display_bindings_bar (win[STA].p, binding, 0, binding_size); wins_doupdate (); - while ((ch = keys_getch (win[STA].p)) != KEY_GENERIC_QUIT) + while ((ch = keys_getch (win[STA].p, NULL)) != KEY_GENERIC_QUIT) { switch (ch) { @@ -654,8 +696,8 @@ custom_sidebar_config (void) else { wins_reinit_panels (); - wins_update_border (); - wins_update_panels (); + wins_update_border (FLAG_ALL); + wins_update_panels (FLAG_ALL); keys_display_bindings_bar (win[STA].p, binding, 0, binding_size); wins_doupdate (); } @@ -681,7 +723,7 @@ custom_confwin_init (struct window *confwin, char *label) { erase_window_part (confwin->p, confwin->x, confwin->y, confwin->x + confwin->w, confwin->y + confwin->h); - (void)delwin (confwin->p); + delwin (confwin->p); } wins_get_config (); @@ -851,7 +893,7 @@ custom_color_config (void) char label[BUFSIZ]; conf_win.p = 0; - (void)snprintf (label, BUFSIZ, _("color theme")); + strncpy (label, _("color theme"), BUFSIZ); custom_confwin_init (&conf_win, label); mark_fore = NBUSERCOLORS; mark_back = SIZE - 1; @@ -860,7 +902,7 @@ custom_color_config (void) display_color_config (&conf_win, &mark_fore, &mark_back, cursor, theme_changed); clear (); - while ((ch = keys_getch (win[STA].p)) != KEY_GENERIC_QUIT) + while ((ch = keys_getch (win[STA].p, NULL)) != KEY_GENERIC_QUIT) { need_reset = 0; theme_changed = 0; @@ -953,7 +995,7 @@ custom_color_theme_name (char *theme_name) }; if (!colorize) - (void)snprintf (theme_name, BUFSIZ, "0"); + strncpy (theme_name, "0", BUFSIZ); else { pair_content (COLR_CUSTOM, &color[0], &color[1]); @@ -969,8 +1011,7 @@ custom_color_theme_name (char *theme_name) /* NOTREACHED */ } } - (void)snprintf (theme_name, BUFSIZ, "%s on %s", color_name[0], - color_name[1]); + snprintf (theme_name, BUFSIZ, "%s on %s", color_name[0], color_name[1]); } } @@ -980,6 +1021,7 @@ print_general_options (WINDOW *win, struct conf *conf) { enum { AUTO_SAVE, + AUTO_GC, PERIODIC_SAVE, CONFIRM_QUIT, CONFIRM_DELETE, @@ -995,6 +1037,7 @@ print_general_options (WINDOW *win, struct conf *conf) int y; char *opt[NB_OPTIONS] = { _("auto_save = "), + _("auto_gc = "), _("periodic_save = "), _("confirm_quit = "), _("confirm_delete = "), @@ -1012,7 +1055,13 @@ print_general_options (WINDOW *win, struct conf *conf) 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]); + 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[PERIODIC_SAVE]); custom_apply_attr (win, ATTR_HIGHEST); mvwprintw (win, y, XPOS + 4 + strlen (opt[PERIODIC_SAVE]), "%d", conf->periodic_save); @@ -1021,41 +1070,41 @@ print_general_options (WINDOW *win, struct conf *conf) _("(if not null, automatically save data every 'periodic_save' " "minutes)")); y += YOFF; - mvwprintw (win, y, XPOS, "[3] %s ", opt[CONFIRM_QUIT]); + 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, "[4] %s ", opt[CONFIRM_DELETE]); + 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, "[5] %s ", opt[SKIP_SYSTEM_DIAGS]); + mvwprintw (win, y, XPOS, "[6] %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)")); y += YOFF; - mvwprintw (win, y, XPOS, "[6] %s ", opt[SKIP_PROGRESS_BAR]); + mvwprintw (win, y, XPOS, "[7] %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)")); y += YOFF; - mvwprintw (win, y, XPOS, "[7] %s ", opt[WEEK_BEGINS_MONDAY]); + mvwprintw (win, y, XPOS, "[8] %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)")); y += YOFF; - mvwprintw (win, y, XPOS, "[8] %s ", opt[OUTPUT_DATE_FMT]); + 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); @@ -1063,7 +1112,7 @@ print_general_options (WINDOW *win, struct conf *conf) mvwprintw (win, y + 1, XPOS, _("(Format of the date to be displayed in non-interactive mode)")); y += YOFF; - mvwprintw (win, y, XPOS, "[9] %s ", opt[INPUT_DATE_FMT]); + 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); @@ -1110,7 +1159,7 @@ custom_general_config (struct conf *conf) clear (); custom_set_swsiz (&cwin); - (void)snprintf (cwin.label, BUFSIZ, _("general options")); + strncpy (cwin.label, _("general options"), BUFSIZ); wins_scrollwin_init (&cwin); wins_show (cwin.win.p, cwin.label); status_mesg (number_str, keys); @@ -1134,6 +1183,9 @@ custom_general_config (struct conf *conf) 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) { @@ -1147,32 +1199,32 @@ custom_general_config (struct conf *conf) } status_mesg (number_str, keys); break; - case '3': + case '4': conf->confirm_quit = !conf->confirm_quit; break; - case '4': + case '5': conf->confirm_delete = !conf->confirm_delete; break; - case '5': + case '6': conf->skip_system_dialogs = !conf->skip_system_dialogs; break; - case '6': + case '7': conf->skip_progress_bar = !conf->skip_progress_bar; break; - case '7': + case '8': calendar_change_first_day_of_week (); break; - case '8': + case '9': status_mesg (output_datefmt_str, ""); - (void)strncpy (buf, conf->output_datefmt, - strlen (conf->output_datefmt) + 1); + 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); + strncpy (conf->output_datefmt, buf, strlen (buf) + 1); } status_mesg (number_str, keys); break; - case '9': + case '0': status_mesg (input_datefmt_str, ""); if (updatestring (win[STA].p, &buf, 0, 1) == 0) { @@ -1240,7 +1292,7 @@ print_keys_bindings (WINDOW *win, int selected_row, int selected_elm, int yoff) int nbkeys; nbkeys = keys_action_count_keys (action); - (void)snprintf (actionstr, BUFSIZ, "%s", keys_get_label (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); @@ -1312,7 +1364,7 @@ custom_keys_config (void) clear (); custom_set_swsiz (&kwin); nbdisplayed = (kwin.win.h - LABELLINES) / LINESPERKEY; - (void)snprintf (kwin.label, BUFSIZ, _("keys configuration")); + strncpy (kwin.label, _("keys configuration"), BUFSIZ); wins_scrollwin_init (&kwin); wins_show (kwin.win.p, kwin.label); custom_keys_config_bar (); @@ -1326,7 +1378,7 @@ custom_keys_config (void) { int ch; - ch = keys_getch (win[STA].p); + ch = keys_getch (win[STA].p, NULL); switch (ch) { case KEY_MOVE_UP: @@ -110,7 +110,7 @@ day_cmp_start (struct day_item *a, struct day_item *b) 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. */ @@ -148,10 +148,10 @@ day_store_events (long date) llist_item_t *i; int e_nb = 0; - LLIST_FIND_FOREACH (&eventlist, date, event_inday, i) + LLIST_FIND_FOREACH_CONT (&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); + day_add_event (EVNT, ev->mesg, ev->note, ev->day, ev->id); e_nb++; } @@ -174,8 +174,7 @@ day_store_recur_events (long date) 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); + day_add_event (RECUR_EVNT, rev->mesg, rev->note, rev->day, rev->id); e_nb++; } @@ -196,11 +195,11 @@ day_store_apoints (long date) int a_nb = 0; LLIST_TS_LOCK (&alist_p); - LLIST_TS_FIND_FOREACH (&alist_p, date, apoint_inday, i) + LLIST_TS_FIND_FOREACH_CONT (&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); + day_add_apoint (APPT, apt->mesg, apt->note, apt->start, apt->dur, + apt->state, 0); a_nb++; } LLIST_TS_UNLOCK (&alist_p); @@ -225,10 +224,13 @@ day_store_recur_apoints (long date) 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); - a_nb++; + 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); @@ -347,14 +349,15 @@ display_item_date (int incolor, struct apoint *i, int type, long date, * Print an item description in the corresponding panel window. */ static void -display_item (int incolor, char *msg, int recur, int note, int len, int y, +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; @@ -362,12 +365,20 @@ display_item (int incolor, char *msg, int recur, int note, int len, int y, ch_note = (note) ? '>' : ' '; if (incolor == 0) custom_apply_attr (win, ATTR_HIGHEST); - if (strlen (msg) < len) + if (utf8_strwidth (msg) < width) mvwprintw (win, y, x, " %c%c%s", ch_recur, ch_note, msg); else { - (void)strncpy (buf, msg, len - 1); - buf[len - 1] = '\0'; + 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) @@ -466,28 +477,28 @@ day_check_if_item (struct date day) const long date = date2sec (day, 0, 0); if (LLIST_FIND_FIRST (&recur_elist, date, recur_event_inday)) - return (1); + 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); + return 1; } LLIST_TS_UNLOCK (&recur_alist_p); if (LLIST_FIND_FIRST (&eventlist, date, event_inday)) - return (1); + return 1; LLIST_TS_LOCK (&alist_p); if (LLIST_TS_FIND_FIRST (&alist_p, date, apoint_inday)) { LLIST_TS_UNLOCK (&alist_p); - return (1); + return 1; } LLIST_TS_UNLOCK (&alist_p); - return (0); + return 0; } static unsigned @@ -539,7 +550,7 @@ day_chk_busy_slices (struct date day, int slicesno, int *slices) LLIST_TS_UNLOCK (&recur_alist_p); LLIST_TS_LOCK (&alist_p); - LLIST_TS_FIND_FOREACH (&alist_p, date, apoint_inday, i) + LLIST_TS_FIND_FOREACH_CONT (&alist_p, date, apoint_inday, i) { struct apoint *apt = LLIST_TS_GET_DATA (i); long start = get_item_time (apt->start); @@ -558,44 +569,91 @@ day_chk_busy_slices (struct date day, int slicesno, int *slices) } /* 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 = date_sec2date_str (time, "%H:%M"); + char *msg_time = _("Enter the new time ([hh:mm]) : "); + char *enter_str = _("Press [Enter] to continue"); + 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; + } +} + +/* Request the user to enter a new time or duration. */ +static int +day_edit_duration (int start, int dur, unsigned *new_duration) { - char *timestr; - char *msg_time = _("Enter the new time ([hh:mm] or [h:mm]) : "); + char *timestr = date_sec2date_str (start + dur, "%H:%M"); + char *msg_time = _("Enter the new time ([hh:mm]) or duration ([+hh:mm]): "); char *enter_str = _("Press [Enter] to continue"); - char *fmt_msg = _("You entered an invalid time, should be [h:mm] or [hh:mm]"); + char *fmt_msg = _("You entered an invalid time, should be [hh:mm]"); + long newtime; + unsigned hr, mn; - while (1) + for (;;) { 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) + if (updatestring (win[STA].p, ×tr, 0, 1) == GETSTRING_VALID) { - status_mesg (fmt_msg, enter_str); - (void)wgetch (win[STA].p); + 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 (timestr); + 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); + day_edit_time (*start, &hr, &mn); newtime = update_time_in_date (*start, hr, mn); if (newtime < *start + *dur) { @@ -606,7 +664,7 @@ update_start_time (long *start, long *dur) else { status_mesg (msg_wrong_time, msg_enter); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); valid_date = 0; } } @@ -616,15 +674,10 @@ update_start_time (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 @@ -638,7 +691,7 @@ static void update_rept (struct rpt **rpt, const long start, struct conf *conf) { const int SINGLECHAR = 2; - int ch, cancel, newfreq, date_entered; + int ch, newfreq, date_entered; long newuntil; char outstr[BUFSIZ]; char *typstr, *freqstr, *timstr; @@ -656,17 +709,16 @@ update_rept (struct rpt **rpt, const long start, struct conf *conf) { 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) + snprintf (typstr, SINGLECHAR, "%c", recur_def2char ((*rpt)->type)); + if (updatestring (win[STA].p, &typstr, 0, 1) == GETSTRING_VALID) { + ch = toupper (*typstr); mem_free (typstr); - return; } else { - ch = toupper (*typstr); mem_free (typstr); + return; } } while ((ch != 'D') && (ch != 'W') && (ch != 'M') && (ch != 'Y')); @@ -675,35 +727,33 @@ update_rept (struct rpt **rpt, const long start, struct conf *conf) { 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 + 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); - (void)wgetch (win[STA].p); + 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)); + 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) + if (updatestring (win[STA].p, &timstr, 0, 1) != GETSTRING_VALID) { mem_free (timstr); return; @@ -732,7 +782,7 @@ update_rept (struct rpt **rpt, const long start, struct conf *conf) if (newuntil < start) { status_mesg (msg_wrong_time, msg_enter); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); date_entered = 0; } else @@ -740,10 +790,10 @@ update_rept (struct rpt **rpt, const long start, struct conf *conf) } else { - (void)snprintf (outstr, BUFSIZ, msg_fmts, - DATEFMT_DESC (conf->input_datefmt)); + snprintf (outstr, BUFSIZ, msg_fmts, + DATEFMT_DESC (conf->input_datefmt)); status_mesg (msg_wrong_date, _(outstr)); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); date_entered = 0; } } @@ -926,7 +976,7 @@ day_erase_item (long date, int item_number, enum eraseflg flag) } else { - return (0); + return 0; } if (p->type == RECUR_EVNT) { @@ -941,7 +991,7 @@ day_erase_item (long date, int item_number, enum eraseflg 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. */ @@ -1033,7 +1083,7 @@ day_item_nb (long date, int day_num, int type) j = LLIST_TS_NEXT (j); } - return (nb_item[type - 1]); + return nb_item[type - 1]; } /* Attach a note to an appointment or event. */ @@ -1045,25 +1095,12 @@ day_edit_note (char *editor) 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); - - if (io_file_is_empty (fullname) > 0) - erase_note (&p->note, ERASE_FORCE); + edit_note (&p->note, editor); date = calendar_get_slctd_day_sec (); switch (p->type) @@ -1091,12 +1128,61 @@ day_edit_note (char *editor) void day_view_note (char *pager) { + struct day_item *p = day_get_item (apoint_hilt ()); + view_note (p->note, pager); +} + +/* Pipe an appointment or event to an external program. */ +void +day_pipe_item (struct conf *conf) +{ + char cmd[BUFSIZ] = ""; + int pout; + int pid; + FILE *fpout; + int item_num; + long date; struct day_item *p; - char fullname[BUFSIZ]; + struct recur_apoint *ra; + struct apoint *a; + struct recur_event *re; + struct event *e; - p = day_get_item (apoint_hilt ()); - if (p->note == NULL) + 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, p->note); - wins_launch_external (fullname, pager); + + wins_prepare_external (); + if ((pid = shell_exec (NULL, &pout, cmd))) + { + fpout = fdopen (pout, "w"); + + item_num = apoint_hilt (); + p = day_get_item (item_num); + date = calendar_get_slctd_day_sec (); + switch (p->type) + { + case RECUR_EVNT: + re = recur_get_event (date, day_item_nb (date, item_num, RECUR_EVNT)); + recur_event_write (re, fpout); + break; + case EVNT: + e = event_get (date, day_item_nb (date, item_num, EVNT)); + event_write (e, fpout); + break; + case RECUR_APPT: + ra = recur_get_apoint (date, day_item_nb (date, item_num, RECUR_APPT)); + recur_apoint_write (ra, fpout); + break; + case APPT: + a = apoint_get (date, day_item_nb (date, item_num, APPT)); + apoint_write (a, fpout); + break; + } + + fclose (fpout); + child_wait (NULL, &pout, pid); + press_any_key (); + } + wins_unprepare_external (); } @@ -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 { \ @@ -131,15 +131,15 @@ daemonize (int status) /* 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); + dup2 (fd, STDIN_FILENO); + dup2 (fd, STDOUT_FILENO); + dup2 (fd, STDERR_FILENO); if (fd > 2) - (void)close (fd); + 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) @@ -165,7 +165,7 @@ dmon_start (int parent_exit_status) if (!io_file_exist (path_conf)) DMON_ABRT (_("Could not access \"%s\": %s\n"), path_conf, strerror (errno)); - custom_load_conf (&conf, 0); + custom_load_conf (&conf); if (!io_file_exist (path_apts)) DMON_ABRT (_("Could not access \"%s\": %s\n"), @@ -194,8 +194,9 @@ dmon_start (int parent_exit_status) DMON_LOG (_("error while sending notification\n")); } - DMON_LOG (_("sleeping at %s for %d seconds\n"), nowstr (), - DMON_SLEEP_TIME); + 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 ()); } diff --git a/src/event.c b/src/event.c index c395ed8..64bc3eb 100644 --- a/src/event.c +++ b/src/event.c @@ -45,21 +45,21 @@ llist_t eventlist; static struct event bkp_cut_event; void -event_free_bkp (enum eraseflg flag) +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); + erase_note (&bkp_cut_event.note); } static void event_free (struct event *ev) { mem_free (ev->mesg); - erase_note (&ev->note, ERASE_FORCE_KEEP_NOTE); + erase_note (&ev->note); mem_free (ev); } @@ -91,7 +91,7 @@ event_llist_free (void) 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 */ @@ -115,11 +115,11 @@ event_new (char *mesg, char *note, long day, int id) unsigned event_inday (struct event *i, long start) { - if (i->day <= start + DAYINSEC && i->day > start) + if (i->day < start + DAYINSEC && i->day >= start) { - return (1); + return 1; } - return (0); + return 0; } /* Write to file the event in user-friendly format */ @@ -131,11 +131,11 @@ event_write (struct event *o, FILE *f) 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); + 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 */ @@ -146,16 +146,16 @@ event_scan (FILE *f, struct tm start, int id, char *note) time_t tstart, t; t = time (NULL); - (void)localtime (&t); + localtime (&t); /* Read the event description */ - (void)fgets (buf, sizeof buf, f); + fgets (buf, sizeof buf, f); nl = strchr (buf, '\n'); if (nl) { *nl = '\0'; } - start.tm_hour = 12; + start.tm_hour = 0; start.tm_min = 0; start.tm_sec = 0; start.tm_isdst = -1; @@ -194,18 +194,16 @@ event_delete_bynum (long start, unsigned num, enum eraseflg flag) switch (flag) { case ERASE_FORCE_ONLY_NOTE: - erase_note (&ev->note, flag); + erase_note (&ev->note); break; case ERASE_CUT: - event_free_bkp (ERASE_FORCE); + event_free_bkp (); event_dup (ev, &bkp_cut_event); - erase_note (&ev->note, ERASE_FORCE_KEEP_NOTE); + erase_note (&ev->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; } @@ -214,8 +212,7 @@ event_delete_bynum (long start, unsigned num, enum eraseflg flag) 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..29ca82b --- /dev/null +++ b/src/getstring.c @@ -0,0 +1,299 @@ +/* + * Calcurse - text-based organizer + * + * Copyright (c) 2004-2011 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; +} @@ -56,6 +56,7 @@ typedef enum HELP_EXPORT, HELP_DISPLACEMENT, HELP_VIEW, + HELP_PIPE, HELP_TAB, HELP_GOTO, HELP_DELETE, @@ -167,7 +168,7 @@ 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")); + strncpy (hwin->label, _("Calcurse help"), BUFSIZ); wins_scrollwin_init (hwin); wins_show (hwin->win.p, hwin->label); } @@ -296,6 +297,10 @@ wanted_page (int ch) page = HELP_VIEW; break; + case KEY_PIPE_ITEM: + page = HELP_PIPE; + break; + case KEY_RAISE_PRIORITY: case KEY_LOWER_PRIORITY: page = HELP_PRIORITY; @@ -314,7 +319,7 @@ wanted_page (int ch) break; } - return (page); + return page; } /* Draws the help screen */ @@ -337,7 +342,7 @@ help_screen (void) hscr[HELP_MAIN].title = _(" Welcome to Calcurse. This is the main help screen.\n"); - (void)snprintf (hscr[HELP_MAIN].text, HELPTEXTSIZ, + 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" @@ -358,7 +363,7 @@ help_screen (void) keys_action_firstkey (KEY_GENERIC_CREDITS)); hscr[HELP_SAVE].title = _("Save\n"); - (void)snprintf (hscr[HELP_SAVE].text, HELPTEXTSIZ, + snprintf (hscr[HELP_SAVE].text, HELPTEXTSIZ, _("Save calcurse data.\n" "Data are splitted into four different files which contain :" "\n\n" @@ -371,7 +376,7 @@ help_screen (void) "automatically before quitting.")); hscr[HELP_IMPORT].title = _("Import\n"); - (void)snprintf (hscr[HELP_IMPORT].text, HELPTEXTSIZ, + 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" @@ -389,7 +394,7 @@ help_screen (void) "the item could not be imported.\n")); hscr[HELP_EXPORT].title = _("Export\n"); - (void)snprintf (hscr[HELP_EXPORT].text, HELPTEXTSIZ, + 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" @@ -404,15 +409,15 @@ help_screen (void) "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), + strncpy (keystr[MOVE_UP], keys_action_allkeys (KEY_MOVE_UP), BUFSIZ); + strncpy (keystr[MOVE_DOWN], keys_action_allkeys (KEY_MOVE_DOWN), BUFSIZ); - (void)strncpy (keystr[MOVE_LEFT], keys_action_allkeys (KEY_MOVE_LEFT), + strncpy (keystr[MOVE_LEFT], keys_action_allkeys (KEY_MOVE_LEFT), BUFSIZ); - (void)strncpy (keystr[MOVE_RIGHT], keys_action_allkeys (KEY_MOVE_RIGHT), + 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, + 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" @@ -439,7 +444,7 @@ help_screen (void) keys_action_firstkey (KEY_END_OF_WEEK)); hscr[HELP_VIEW].title = _("View\n"); - (void)snprintf (hscr[HELP_VIEW].text, HELPTEXTSIZ, + 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. " @@ -451,8 +456,16 @@ help_screen (void) "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, + 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" @@ -467,7 +480,7 @@ help_screen (void) keys_action_firstkey (KEY_GENERIC_CHANGE_VIEW)); hscr[HELP_GOTO].title = _("Goto\n"); - (void)snprintf (hscr[HELP_GOTO].text, HELPTEXTSIZ, + 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" @@ -478,7 +491,7 @@ help_screen (void) keys_action_firstkey (KEY_GENERIC_GOTO_TODAY)); hscr[HELP_DELETE].title = _("Delete\n"); - (void)snprintf (hscr[HELP_DELETE].text, HELPTEXTSIZ, + 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" @@ -492,7 +505,7 @@ help_screen (void) "next time you launch Calcurse.")); hscr[HELP_ADD].title = _("Add\n"); - (void)snprintf (hscr[HELP_ADD].text, HELPTEXTSIZ, + 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" @@ -507,9 +520,9 @@ help_screen (void) "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" + "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" @@ -529,7 +542,7 @@ help_screen (void) keys_action_firstkey (KEY_ADD_ITEM)); hscr[HELP_CUT_PASTE].title = _("Cut and Paste\n"); - (void)snprintf (hscr[HELP_CUT_PASTE].text, HELPTEXTSIZ, + 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" @@ -545,7 +558,7 @@ help_screen (void) keys_action_firstkey (KEY_GENERIC_PASTE)); hscr[HELP_EDIT].title = _("Edit Item\n"); - (void)snprintf (hscr[HELP_EDIT].text, HELPTEXTSIZ, + 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" @@ -562,7 +575,7 @@ help_screen (void) " modified properties next time you launch Calcurse.")); hscr[HELP_ENOTE].title = _("EditNote\n"); - (void)snprintf (hscr[HELP_ENOTE].text, HELPTEXTSIZ, + 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" @@ -583,7 +596,7 @@ help_screen (void) keys_action_firstkey (KEY_EDIT_NOTE)); hscr[HELP_VNOTE].title = _("ViewNote\n"); - (void)snprintf (hscr[HELP_VNOTE].text, HELPTEXTSIZ, + 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" @@ -602,7 +615,7 @@ help_screen (void) keys_action_firstkey (KEY_VIEW_NOTE)); hscr[HELP_PRIORITY].title = _("Priority\n"); - (void)snprintf (hscr[HELP_PRIORITY].text, HELPTEXTSIZ, + 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" @@ -620,7 +633,7 @@ help_screen (void) keys_action_firstkey (KEY_LOWER_PRIORITY)); hscr[HELP_REPEAT].title = _("Repeat\n"); - (void)snprintf (hscr[HELP_REPEAT].text, HELPTEXTSIZ, + 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" @@ -647,7 +660,7 @@ help_screen (void) keys_action_firstkey (KEY_REPEAT_ITEM)); hscr[HELP_FLAG].title = _("Flag Item\n"); - (void)snprintf (hscr[HELP_FLAG].text, HELPTEXTSIZ, + 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" @@ -661,7 +674,7 @@ help_screen (void) "\nand how long before it he gets notified.")); hscr[HELP_CONFIG].title = _("Config\n"); - (void)snprintf (hscr[HELP_CONFIG].text, HELPTEXTSIZ, + 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" @@ -676,7 +689,7 @@ help_screen (void) "\nnext time you launch Calcurse.")); hscr[HELP_GENERAL].title = _("Generic keybindings\n"); - (void)snprintf (hscr[HELP_GENERAL].text, HELPTEXTSIZ, + 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" @@ -707,7 +720,7 @@ help_screen (void) keys_action_firstkey (KEY_GENERIC_SCROLL_DOWN)); hscr[HELP_OTHER].title = _("OtherCmd\n"); - (void)snprintf (hscr[HELP_OTHER].text, HELPTEXTSIZ, + 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" @@ -718,7 +731,7 @@ help_screen (void) keys_action_firstkey (KEY_GENERIC_OTHER_CMD)); hscr[HELP_CREDITS].title = _("Calcurse - text-based organizer"); - (void)snprintf (hscr[HELP_CREDITS].text, HELPTEXTSIZ, + snprintf (hscr[HELP_CREDITS].text, HELPTEXTSIZ, _("\nCopyright (c) 2004-2011 calcurse Development Team\n" "All rights reserved.\n" "\n" @@ -779,7 +792,7 @@ help_screen (void) } wins_scrollwin_display (&hwin); - ch = keys_getch (win[STA].p); + ch = keys_getch (win[STA].p, NULL); } wins_scrollwin_delete (&hwin); if (need_resize) @@ -45,6 +45,7 @@ #include <errno.h> #include "calcurse.h" +#include "sha1.h" #define ICALDATEFMT "%Y%m%d" #define ICALDATETIMEFMT "%Y%m%dT%H%M%S" @@ -136,7 +137,6 @@ static char *ical_recur_type[RECUR_TYPES] = static void progress_bar (progress_bar_t type, int progress) { -#define SLEEPTIME 125000 #define NBFILES 4 #define NBEXPORTED 3 #define LABELENGTH 15 @@ -194,8 +194,6 @@ progress_bar (progress_bar_t type, int progress) custom_remove_attr (win[STA].p, ATTR_HIGHEST); wmove (win[STA].p, 0, 0); wins_wrefresh (win[STA].p); - (void)usleep (SLEEPTIME); -#undef SLEEPTIME #undef NBFILES #undef NBEXPORTED #undef LABELENGTH @@ -217,11 +215,10 @@ get_export_stream (enum export_type type) 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]); + 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]); + snprintf (stream_name, BUFSIZ, "%s/calcurse.%s", get_tempdir (), + file_ext[type]); while (stream == NULL) { @@ -230,18 +227,18 @@ get_export_stream (enum export_type type) if (cancel) { mem_free (stream_name); - return (NULL); + return NULL; } stream = fopen (stream_name, "w"); if (stream == NULL) { status_mesg (wrong_name, press_enter); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); } } mem_free (stream_name); - return (stream); + return stream; } /* @@ -266,8 +263,8 @@ foreach_date_dump (const long date_end, struct rpt *rpt, llist_t *exc, while (date <= date_end && date <= rpt->until) { - if (recur_item_inday (item_first_date, exc, rpt->type, rpt->freq, - rpt->until, date)) + 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); } @@ -297,41 +294,40 @@ foreach_date_dump (const long date_end, struct rpt *rpt, llist_t *exc, static void ical_export_valarm (FILE *stream) { - (void)fprintf (stream, "BEGIN:VALARM\n"); + fputs ("BEGIN:VALARM\n", stream); pthread_mutex_lock (&nbar.mutex); - (void)fprintf (stream, "TRIGGER:-P%dS\n", nbar.cntdwn); + 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"); + fputs ("ACTION:DISPLAY\n", stream); + fputs ("END:VALARM\n", stream); } /* 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"); + fputs ("BEGIN:VCALENDAR\n", stream); + fprintf (stream, "PRODID:-//calcurse//NONSGML v%s//EN\n", VERSION); + fputs ("VERSION:2.0\n", stream); } 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 %s %%w\n", _("Week")); - (void)fprintf (stream, "\n"); + 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 %s %%w\n", _("Week")); + fputc ('\n', stream); } /* Export footer. */ static void ical_export_footer (FILE *stream) { - (void)fprintf (stream, "END:VCALENDAR\n"); + fputs ("END:VCALENDAR\n", stream); } static void @@ -350,36 +346,36 @@ ical_export_recur_events (FILE *stream) { 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); + 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); - (void)fprintf (stream, ";UNTIL=%s\n", ical_date); + fprintf (stream, ";UNTIL=%s\n", ical_date); } else - (void)fprintf (stream, "\n"); + fputc ('\n', stream); if (LLIST_FIRST (&rev->exc)) { - (void)fprintf (stream, "EXDATE:"); + fputs ("EXDATE:", stream); 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); + fprintf (stream, "%s", ical_date); if (LLIST_NEXT (j)) - (void)fprintf (stream, ","); + fputc (',', stream); else - (void)fprintf (stream, "\n"); + fputc ('\n', stream); } } - (void)fprintf (stream, "SUMMARY:%s\n", rev->mesg); - (void)fprintf (stream, "END:VEVENT\n"); + fprintf (stream, "SUMMARY:%s\n", rev->mesg); + fputs ("END:VEVENT\n", stream); } } @@ -391,7 +387,7 @@ pcal_dump_event (FILE *stream, long event_date, long event_dur, char pcal_date[BUFSIZ]; date_sec2date_fmt (event_date, "%b %d", pcal_date); - (void)fprintf (stream, "%s %s\n", pcal_date, event_mesg); + fprintf (stream, "%s %s\n", pcal_date, event_mesg); } /* Format and dump appointment data to a pcal formatted file. */ @@ -404,8 +400,8 @@ pcal_dump_apoint (FILE *stream, long apoint_date, long apoint_dur, 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); + fprintf (stream, "%s ", pcal_date); + fprintf (stream, "(%s -> %s) %s\n", pcal_beg, pcal_end, apoint_mesg); } static void @@ -414,11 +410,10 @@ 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"); + 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) { @@ -429,23 +424,22 @@ pcal_export_recur_events (FILE *stream) { 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); + 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); + 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); + 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); + 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); + fprintf (stream, "%s %s\n", pcal_date, rev->mesg); break; default: EXIT (_("incoherent repetition type")); @@ -474,10 +468,10 @@ ical_export_events (FILE *stream) { 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"); + fputs ("BEGIN:VEVENT\n", stream); + fprintf (stream, "DTSTART:%s\n", ical_date); + fprintf (stream, "SUMMARY:%s\n", ev->mesg); + fputs ("END:VEVENT\n", stream); } } @@ -486,13 +480,13 @@ pcal_export_events (FILE *stream) { llist_item_t *i; - (void)fprintf (stream, "\n# ======\n# Events\n# ======\n"); + 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); } - (void)fprintf (stream, "\n"); + fputc ('\n', stream); } /* Export recurrent appointments. */ @@ -509,40 +503,40 @@ ical_export_recur_apoints (FILE *stream) 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); + 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); - (void)fprintf (stream, ";UNTIL=%s\n", ical_date); + fprintf (stream, ";UNTIL=%s\n", ical_date); } else - (void)fprintf (stream, "\n"); + fputc ('\n', stream); if (LLIST_FIRST (&rapt->exc)) { - (void)fprintf (stream, "EXDATE:"); + fputs ("EXDATE:", stream); 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); + fprintf (stream, "%s", ical_date); if (LLIST_NEXT (j)) - (void)fprintf (stream, ","); + fputc (',', stream); else - (void)fprintf (stream, "\n"); + fputc ('\n', stream); } } - (void)fprintf (stream, "SUMMARY:%s\n", rapt->mesg); + fprintf (stream, "SUMMARY:%s\n", rapt->mesg); if (rapt->state & APOINT_NOTIFY) ical_export_valarm (stream); - (void)fprintf (stream, "END:VEVENT\n"); + fputs ("END:VEVENT\n", stream); } LLIST_TS_UNLOCK (&recur_alist_p); } @@ -553,11 +547,10 @@ 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"); + 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) { @@ -571,25 +564,25 @@ pcal_export_recur_apoints (FILE *stream) { 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); + 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); + 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); + 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); + 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); + fprintf (stream, "%s (%s -> %s) %s\n", pcal_date, pcal_beg, + pcal_end, rapt->mesg); break; default: EXIT (_("incoherent repetition type")); @@ -620,13 +613,13 @@ ical_export_apoints (FILE *stream) { 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:PT0H0M%ldS\n", apt->dur); - (void)fprintf (stream, "SUMMARY:%s\n", apt->mesg); + fputs ("BEGIN:VEVENT\n", stream); + fprintf (stream, "DTSTART:%s\n", ical_datetime); + fprintf (stream, "DURATION:PT0H0M%ldS\n", apt->dur); + fprintf (stream, "SUMMARY:%s\n", apt->mesg); if (apt->state & APOINT_NOTIFY) ical_export_valarm (stream); - (void)fprintf (stream, "END:VEVENT\n"); + fputs ("END:VEVENT\n", stream); } LLIST_TS_UNLOCK (&alist_p); } @@ -636,7 +629,7 @@ pcal_export_apoints (FILE *stream) { llist_item_t *i; - (void)fprintf (stream, "\n# ============\n# Appointments\n# ============\n"); + fputs ("\n# ============\n# Appointments\n# ============\n", stream); LLIST_TS_LOCK (&alist_p); LLIST_TS_FOREACH (&alist_p, i) { @@ -644,7 +637,7 @@ pcal_export_apoints (FILE *stream) pcal_dump_apoint (stream, apt->start, apt->dur, apt->mesg); } LLIST_TS_UNLOCK (&alist_p); - (void)fprintf (stream, "\n"); + fputc ('\n', stream); } /* Export todo items. */ @@ -659,10 +652,10 @@ ical_export_todo (FILE *stream) if (todo->id < 0) /* completed items */ continue; - (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"); + fputs ("BEGIN:VTODO\n", stream); + fprintf (stream, "PRIORITY:%d\n", todo->id); + fprintf (stream, "SUMMARY:%s\n", todo->mesg); + fputs ("END:VTODO\n", stream); } } @@ -671,17 +664,17 @@ pcal_export_todo (FILE *stream) { llist_item_t *i; - (void)fprintf (stream, "#\n# Todos\n#\n"); + 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; - (void)fprintf (stream, "note all "); - (void)fprintf (stream, "%d. %s\n", todo->id, todo->mesg); + fputs ("note all ", stream); + fprintf (stream, "%d. %s\n", todo->id, todo->mesg); } - (void)fprintf (stream, "\n"); + fputc ('\n', stream); } /* Append a line to a file. */ @@ -730,15 +723,15 @@ io_init (char *cfile, char *datadir) 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); + 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 { @@ -747,22 +740,22 @@ io_init (char *cfile, char *datadir) { 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); + 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) { - (void)snprintf (path_apts, BUFSIZ, "%s/" APTS_PATH, home); + snprintf (path_apts, BUFSIZ, "%s/" APTS_PATH, home); } else { - (void)snprintf (apts_file, BUFSIZ, "%s", cfile); - (void)strncpy (path_apts, apts_file, BUFSIZ); + 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) @@ -774,7 +767,7 @@ io_init (char *cfile, char *datadir) { case 'N': case 'n': - printf (_("aborting...\n")); + puts (_("aborting...\n")); exit_calcurse (EXIT_FAILURE); break; @@ -789,12 +782,12 @@ io_init (char *cfile, char *datadir) else { printf (_("%s successfully created\n"), path_apts); - printf (_("starting interactive mode...\n")); + puts (_("starting interactive mode...\n")); } break; default: - printf (_("aborting...\n")); + puts (_("aborting...\n")); exit_calcurse (EXIT_FAILURE); break; } @@ -809,9 +802,10 @@ io_extract_data (char *dst_data, const char *org, int len) { int i; + for (; *org == ' ' || *org == '\t'; org++); for (i = 0; i < len - 1; i++) { - if (*org == '\n' || *org == '\0') + if (*org == '\n' || *org == '\0' || *org == '#') break; *dst_data++ = *org++; } @@ -849,8 +843,9 @@ io_save_conf (struct conf *conf) "# 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" + "# For a variable to be unset its value must be blank, followed by an\n" + "# empty line. 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; @@ -860,115 +855,118 @@ io_save_conf (struct conf *conf) 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 ()); + fprintf (fp, "%s\n", config_txt); + + fputs ("# If this option is set to yes, " + "automatic save is done when quitting\n", fp); + fputs ("auto_save=", fp); + fprintf (fp, "%s\n", (conf->auto_save) ? "yes" : "no"); + + fputs ("\n# If this option is set to yes, " + "the GC is run automatically when quitting\n", fp); + fputs ("auto_gc=", fp); + fprintf (fp, "%s\n", (conf->auto_gc) ? "yes" : "no"); + + fputs ("\n# If not null, perform automatic saves every " + "'periodic_save' minutes\n", fp); + fputs ("periodic_save=", fp); + fprintf (fp, "%d\n", conf->periodic_save); + + fputs ("\n# If this option is set to yes, " + "confirmation is required before quitting\n", fp); + fputs ("confirm_quit=", fp); + fprintf (fp, "%s\n", (conf->confirm_quit) ? "yes" : "no"); + + fputs ("\n# If this option is set to yes, " + "confirmation is required before deleting an event\n", fp); + fputs ("confirm_delete=", fp); + fprintf (fp, "%s\n", (conf->confirm_delete) ? "yes" : "no"); + + fputs ("\n# If this option is set to yes, messages about loaded and " + "saved data will not be displayed\n", fp); + fputs ("skip_system_dialogs=", fp); + fprintf (fp, "%s\n", (conf->skip_system_dialogs) ? "yes" : "no"); + + fputs ("\n# If this option is set to yes, progress bar appearing " + "when saving data will not be displayed\n", fp); + fputs ("skip_progress_bar=", fp); + fprintf (fp, "%s\n", (conf->skip_progress_bar) ? "yes" : "no"); + + fputs ("\n# Default calendar view (0)monthly (1)weekly:\n", fp); + fputs ("calendar_default_view=", fp); + fprintf (fp, "%d\n", calendar_get_view ()); + + fputs ("\n# If this option is set to yes, " + "monday is the first day of the week, else it is sunday\n", fp); + fputs ("week_begins_on_monday=", fp); + fprintf (fp, "%s\n", (calendar_week_begins_on_monday ())? "yes" : "no"); + + fputs ("\n# This is the color theme used for menus :\n", fp); + fputs ("color-theme=", fp); + fprintf (fp, "%s\n", theme_name); + + fputs ("\n# This is the layout of the calendar :\n", fp); + fputs ("layout=", fp); + fprintf (fp, "%d\n", wins_layout ()); + + fputs ("\n# Width ( percentage, 0 being minimun width, fp) " + "of the side bar :\n", fp); + fputs ("side-bar_width=", fp); + 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); + fputs ("\n# If this option is set to yes, " + "notify-bar will be displayed :\n", fp); + fputs ("notify-bar_show=", fp); + fprintf (fp, "%s\n", (nbar.show) ? "yes" : "no"); + + fputs ("\n# Format of the date to be displayed inside notify-bar :\n", fp); + fputs ("notify-bar_date=", fp); + fprintf (fp, "%s\n", nbar.datefmt); + + fputs ("\n# Format of the time to be displayed inside notify-bar :\n", fp); + fputs ("notify-bar_clock=", fp); + fprintf (fp, "%s\n", nbar.timefmt); + + fputs ("\n# Warn user if he has an appointment within next " + "'notify-bar_warning' seconds :\n", fp); + fputs ("notify-bar_warning=", fp); + fprintf (fp, "%d\n", nbar.cntdwn); + + fputs ("\n# Command used to notify user of " + "an upcoming appointment :\n", fp); + fputs ("notify-bar_command=", fp); + fprintf (fp, "%s\n", nbar.cmd); + + fputs ("\n# Notify all appointments instead of flagged ones only\n", fp); + fputs ("notify-all=", fp); + fprintf (fp, "%s\n", (nbar.notify_all) ? "yes" : "no"); + + fputs ("\n# Format of the date to be displayed " + "in non-interactive mode :\n", fp); + fputs ("output_datefmt=", fp); + fprintf (fp, "%s\n", conf->output_datefmt); + + fputs ("\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", fp); + fputs ("input_datefmt=", fp); + 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"); + fputs ("\n# If this option is set to yes, " + "calcurse will run in background to get notifications " + "after exiting\n", fp); + fputs ("notify-daemon_enable=", fp); + 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"); + fputs ("\n# If this option is set to yes, " + "activity will be logged when running in background\n", fp); + fputs ("notify-daemon_log=", fp); + fprintf (fp, "%s\n", dmon.log ? "yes" : "no"); file_close (fp, __FILE_POS__); @@ -1024,10 +1022,7 @@ io_save_todo (void) 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); + todo_write (todo, fp); } file_close (fp, __FILE_POS__); @@ -1092,7 +1087,7 @@ io_save_cal (struct conf *conf, enum save_display display) && display != IO_SAVE_DISPLAY_MARK) { status_mesg (save_success, enter); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); } pthread_mutex_unlock (&io_save_mutex); @@ -1114,7 +1109,7 @@ 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); @@ -1128,7 +1123,7 @@ io_load_app (void) c = getc (data_file); if (c == EOF) break; - (void)ungetc (c, data_file); + ungetc (c, data_file); /* Read the date first: it is common to both events * and appointments. @@ -1152,7 +1147,7 @@ io_load_app (void) { EXIT (_("no event nor appointment found")); } - (void)ungetc (c, data_file); + ungetc (c, data_file); /* Read the remaining informations. */ if (is_appointment) @@ -1177,38 +1172,38 @@ io_load_app (void) if (c == '{') { - (void)ungetc (c, data_file); + 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); + ungetc (c, data_file); fscanf (data_file, "} "); until.tm_year = 0; } else if (c == '-') { - (void)ungetc (c, data_file); + 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); + ungetc (c, data_file); recur_exc_scan (&exc, data_file); c = getc (data_file); } else { - (void)ungetc (c, data_file); + ungetc (c, data_file); fscanf (data_file, "} "); } } else if (c == '!') { // endless item with exceptions - (void)ungetc (c, data_file); + ungetc (c, data_file); recur_exc_scan (&exc, data_file); c = getc (data_file); until.tm_year = 0; @@ -1220,21 +1215,19 @@ io_load_app (void) } } else - (void)ungetc (c, data_file); + 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'; + note_read (note, data_file); notep = note; - getc (data_file); } else { notep = NULL; - (void)ungetc (c, data_file); + ungetc (c, data_file); } /* @@ -1246,13 +1239,13 @@ io_load_app (void) c = getc (data_file); if (c == '!') { - (void)ungetc (c, data_file); + ungetc (c, data_file); fscanf (data_file, " ! "); state |= APOINT_NOTIFY; } else { - (void)ungetc (c, data_file); + ungetc (c, data_file); fscanf (data_file, " | "); state = 0L; } @@ -1297,13 +1290,13 @@ io_load_todo (void) 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); + wgetch (win[STA].p); } for (;;) { @@ -1319,20 +1312,16 @@ io_load_todo (void) else { id = 9; - (void)ungetc (c, data_file); + 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); - } + note_read (note, data_file); else note[0] = '\0'; /* Then read todo description. */ - (void)fgets (buf, sizeof buf, data_file); + fgets (buf, sizeof buf, data_file); newline = strchr (buf, '\n'); if (newline) *newline = '\0'; @@ -1526,8 +1515,8 @@ io_check_dir (char *dir, int *missing) { if (errno != EEXIST) { - (void)fprintf (stderr, _("FATAL ERROR: could not create %s: %s\n"), - dir, strerror (errno)); + fprintf (stderr, _("FATAL ERROR: could not create %s: %s\n"), dir, + strerror (errno)); exit_calcurse (EXIT_FAILURE); } } @@ -1549,7 +1538,7 @@ io_file_exist (char *file) if ((fd = fopen (file, "r")) == NULL) return 0; - (void)fclose (fd); + fclose (fd); return 1; } @@ -1566,8 +1555,8 @@ io_check_file (char *file, int *missing) (*missing)++; if ((fd = fopen (file, "w")) == NULL) { - (void)fprintf (stderr, _("FATAL ERROR: could not create %s: %s\n"), - file, strerror (errno)); + fprintf (stderr, _("FATAL ERROR: could not create %s: %s\n"), file, + strerror (errno)); exit_calcurse (EXIT_FAILURE); } file_close (fd, __FILE_POS__); @@ -1620,12 +1609,12 @@ io_startup_screen (unsigned skip_dialogs, int no_data_file) if (no_data_file != 0) { status_mesg (welcome_mesg, enter); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); } else if (!skip_dialogs) { status_mesg (data_mesg, enter); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); } } @@ -1681,7 +1670,7 @@ io_export_data (enum export_type type, struct conf *conf) if (!conf->skip_system_dialogs && ui_mode == UI_CURSES) { status_mesg (success, enter); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); } } @@ -1730,7 +1719,7 @@ ical_log_init (FILE *log, float version) "+-------------------------------------------------------------------+\n\n"; if (log) - (void)fprintf (log, header, version); + fprintf (log, header, version); } /* @@ -1746,7 +1735,7 @@ ical_log (FILE *log, ical_types_e type, unsigned lineno, char *msg) RETURN_IF (type < 0 || type >= ICAL_TYPES, _("unknown ical type")); if (log) - (void)fprintf (log, "%s [%d]: %s\n", typestr[type], lineno, msg); + fprintf (log, "%s [%d]: %s\n", typestr[type], lineno, msg); } static void @@ -1754,7 +1743,7 @@ ical_store_todo (int priority, char *mesg, char *note) { todo_add (mesg, priority, note); mem_free (mesg); - erase_note (¬e, ERASE_FORCE_KEEP_NOTE); + erase_note (¬e); } static void @@ -1786,7 +1775,7 @@ ical_store_event (char *mesg, char *note, long day, long end, ical_rpt_t *rpt, event_new (mesg, note, day, EVENTID); } mem_free (mesg); - erase_note (¬e, ERASE_FORCE_KEEP_NOTE); + erase_note (¬e); } static void @@ -1808,7 +1797,7 @@ ical_store_apoint (char *mesg, char *note, long start, long dur, apoint_new (mesg, note, start, dur, state); } mem_free (mesg); - erase_note (¬e, ERASE_FORCE_KEEP_NOTE); + erase_note (¬e); } /* @@ -2292,7 +2281,7 @@ ical_read_exdate (llist_t *exc, FILE *log, char *exstr, unsigned *noskipped, char buf[BUFSIZ]; const int buflen = q - p; - (void)strncpy (buf, p, buflen); + strncpy (buf, p, buflen); buf[buflen] = '\0'; date = ical_datetime2long (buf, NULL); ical_add_exc (exc, date); @@ -2314,43 +2303,37 @@ 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]; + char *sha1 = mem_malloc (SHA1_DIGESTLEN * 2 + 1); + char *p, *notestr, 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); + sha1_digest (notestr, sha1); + snprintf (fullnotename, BUFSIZ, "%s%s", path_notes, sha1); + fdo = fopen (fullnotename, "w"); + EXIT_IF (fdo == NULL, _("Warning: could not open %s, Aborting..."), + fullnotename); + fprintf (fdo, "%s", notestr); file_close (fdo, __FILE_POS__); mem_free (notestr); - return notename; + return sha1; } } else @@ -2694,7 +2677,7 @@ get_import_stream (enum export_type type) if (stream == NULL) { status_mesg (wrong_file, press_enter); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); } } mem_free (stream_name); @@ -2714,10 +2697,7 @@ io_import_data (enum import_type type, struct conf *conf, 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 stats_str[4][BUFSIZ]; char buf[BUFSIZ], lstore[BUFSIZ]; FILE *stream = NULL; struct io_file *log; @@ -2780,6 +2760,14 @@ io_import_data (enum import_type type, struct conf *conf, char *stream_name) 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); @@ -2787,19 +2775,18 @@ io_import_data (enum import_type type, struct conf *conf, char *stream_name) { char read[BUFSIZ], stat[BUFSIZ]; - (void)snprintf (read, BUFSIZ, proc_report, stats.lines); - (void)snprintf (stat, BUFSIZ, lines_stats_interactive, stats.apoints, - stats.events, stats.todos, stats.skipped); + 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); - (void)wgetch (win[STA].p); + 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"); + 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 @@ -2823,13 +2810,13 @@ io_log_init (void) struct io_file *log; snprintf (logprefix, BUFSIZ, "%s/calcurse_log.", get_tempdir ()); - logname = new_tempfile (logprefix, NOTESIZ); + 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...")); - (void)snprintf (log->name, sizeof (log->name), "%s%s", logprefix, logname); + snprintf (log->name, sizeof (log->name), "%s%s", logprefix, logname); mem_free (logname); log->fd = fopen (log->name, "w"); if (log->fd == NULL) @@ -2846,7 +2833,7 @@ void io_log_print (struct io_file *log, int line, 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 @@ -2864,8 +2851,8 @@ io_log_display (struct io_file *log, char *msg, char *pager) { char cmd[BUFSIZ]; - (void)snprintf (cmd, BUFSIZ, "%s %s", pager, log->name); - (void)system (cmd); + snprintf (cmd, BUFSIZ, "%s %s", pager, log->name); + system (cmd); } } else @@ -2910,7 +2897,7 @@ io_psave_thread (void *arg) for (;;) { - (void)sleep (delay * MININSEC); + sleep (delay * MININSEC); io_save_cal (config, IO_SAVE_DISPLAY_MARK); } } @@ -2965,12 +2952,12 @@ io_set_lock (void) 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); + 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 @@ -3023,7 +3010,7 @@ io_get_pid (char *file) if (fscanf (fp, "%u", &pid) != 1) return 0; - (void)fclose (fp); + fclose (fp); return pid; } @@ -3052,3 +3039,36 @@ io_file_is_empty (char *file) 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; +} @@ -81,16 +81,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"}, @@ -124,7 +125,7 @@ dump_intro (FILE *fd) "# 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); + fprintf (fd, "%s\n", intro); } void @@ -170,7 +171,7 @@ keys_dump_defaults (char *file) dump_intro (fd); for (i = 0; i < NBKEYS; i++) - (void)fprintf (fd, "%s %s\n", keydef[i].label, keydef[i].binding); + fprintf (fd, "%s %s\n", keydef[i].label, keydef[i].binding); file_close (fd, __FILE_POS__); } @@ -193,11 +194,26 @@ keys_get_action (int pressed) } enum key -keys_getch (WINDOW *win) +keys_getch (WINDOW *win, int *count) { - int 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); - ch = wgetch (win); switch (ch) { case KEY_RESIZE: @@ -258,7 +274,7 @@ del_key_str (enum key action, int key) if (action < 0 || action > NBKEYS) return; - (void)strncpy (oldstr, keys_int2str (key), BUFSIZ); + strncpy (oldstr, keys_int2str (key), BUFSIZ); for (i = &keys[action]; *i; i = &(*i)->next) { if (!strcmp ((*i)->str, oldstr)) @@ -391,7 +407,7 @@ keys_action_nkey (enum key action, int keynum) return key->str; i++; } - return (char *)0; + return NULL; } char * @@ -407,8 +423,8 @@ keys_action_allkeys (enum key action) 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); + strncat (keystr, i->str, MAXLEN - 1); + strncat (keystr, CHAR_SPACE, 1); } return keystr; @@ -424,22 +440,22 @@ keys_format_label (char *key, int keylen) int i; if (keylen > BUFSIZ) - return (char *)0; + return NULL; bzero (fmtkey, sizeof (fmtkey)); if (len == 0) - (void)snprintf (fmtkey, sizeof (fmtkey), "?"); + strncpy (fmtkey, "?", sizeof (fmtkey)); else if (len <= keylen) { for (i = 0; i < keylen - len; i++) fmtkey[i] = ' '; - (void)strncat (fmtkey, key, keylen); + strncat (fmtkey, key, keylen); } else { for (i = 0; i < keylen - 1; i++) fmtkey[i] = key[i]; - (void)strncat (fmtkey, dot, strlen (dot)); + strncat (fmtkey, dot, strlen (dot)); } return fmtkey; } @@ -463,15 +479,14 @@ keys_display_bindings_bar (WINDOW *win, struct binding **binding, int first_key, 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); + 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); + 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); @@ -567,6 +582,8 @@ keys_popup_info (enum key key) _("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"); info[KEY_VIEW_NOTE] = @@ -583,7 +600,7 @@ keys_popup_info (enum key key) #define WINCOL (col - 4) infowin = popup (WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2, keydef[key].label, info[key], 1); - (void)keys_getch (infowin); + keys_getch (infowin, NULL); delwin (infowin); #undef WINROW #undef WINCOL @@ -597,7 +614,7 @@ keys_save_bindings (FILE *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 @@ -624,7 +641,7 @@ keys_fill_missing (void) { char *p, tmpbuf[BUFSIZ]; - (void)strncpy (tmpbuf, keydef[i].binding, BUFSIZ); + strncpy (tmpbuf, keydef[i].binding, BUFSIZ); p = tmpbuf; for (;;) { diff --git a/src/llist.c b/src/llist.c index eeded6b..a85cfa9 100644 --- a/src/llist.c +++ b/src/llist.c @@ -43,6 +43,7 @@ void llist_init (llist_t *l) { l->head = NULL; + l->tail = NULL; } /* @@ -60,6 +61,7 @@ llist_free (llist_t *l) } l->head = NULL; + l->tail = NULL; } /* @@ -113,6 +115,19 @@ llist_next (llist_item_t *i) } /* + * Return the successor of a list item if it is matched by some filter + * callback. Return NULL otherwise. + */ +llist_item_t * +llist_next_filter (llist_item_t *i, long data, llist_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 * @@ -128,7 +143,6 @@ void llist_add (llist_t *l, void *data) { llist_item_t *o = mem_malloc (sizeof (llist_item_t)); - llist_item_t *i; if (o) { @@ -136,12 +150,11 @@ llist_add (llist_t *l, void *data) o->next = NULL; if (!l->head) - l->head = o; + l->head = l->tail = o; else { - for (i = l->head; i->next; i = i->next) - ; - i->next = o; + l->tail->next = o; + l->tail = o; } } } @@ -161,7 +174,12 @@ llist_add_sorted (llist_t *l, void *data, llist_fn_cmp_t fn_cmp) o->next = NULL; if (!l->head) - l->head = o; + 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; @@ -198,6 +216,9 @@ llist_remove (llist_t *l, llist_item_t *i) { if (j) j->next = i->next; + if (i == l->tail) + l->tail = j; + mem_free (i); } } diff --git a/src/llist.h b/src/llist.h index d7e4249..8833c66 100644 --- a/src/llist.h +++ b/src/llist.h @@ -44,6 +44,7 @@ struct llist_item { typedef struct llist llist_t; struct llist { struct llist_item *head; + struct llist_item *tail; }; typedef int (*llist_fn_cmp_t) (void *, void *); @@ -64,6 +65,7 @@ void llist_free_inner (llist_t *, llist_fn_free_t); llist_item_t *llist_first (llist_t *); llist_item_t *llist_nth (llist_t *, int); llist_item_t *llist_next (llist_item_t *); +llist_item_t *llist_next_filter (llist_item_t *, long, llist_fn_match_t); llist_item_t *llist_find_first (llist_t *, long, llist_fn_match_t); llist_item_t *llist_find_next (llist_item_t *, long, llist_fn_match_t); llist_item_t *llist_find_nth (llist_t *, int, long, llist_fn_match_t); @@ -71,6 +73,8 @@ 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,6 +86,9 @@ 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 *); diff --git a/src/llist_ts.h b/src/llist_ts.h index 0f90024..0822a3d 100644 --- a/src/llist_ts.h +++ b/src/llist_ts.h @@ -38,6 +38,7 @@ typedef struct llist_ts llist_ts_t; struct llist_ts { llist_item_t *head; + llist_item_t *tail; pthread_mutex_t mutex; }; @@ -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) @@ -176,7 +176,7 @@ dbg_malloc (size_t size, const char *pos) unsigned *buf; if (size == 0) - return (void *)0; + return NULL; size = EXTRA_SPACE + (size + sizeof (unsigned) - 1) / sizeof (unsigned); buf = xmalloc (size * sizeof (unsigned)); @@ -197,13 +197,13 @@ 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); size *= nmemb; if ((buf = dbg_malloc (size, pos)) == NULL) - return (void *)0; + return NULL; bzero (buf, size); @@ -216,16 +216,16 @@ 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; if (new_size == 0) - return (void *)0; + return NULL; EXIT_IF (nmemb > SIZE_MAX / size, _("overflow at %s"), pos); if ((buf = dbg_malloc (new_size, pos)) == NULL) - return (void *)0; + return NULL; old_size = *((unsigned *)ptr - EXTRA_SPACE_START + BLK_SIZE); cpy_size = (old_size > new_size) ? new_size : old_size; @@ -243,11 +243,11 @@ dbg_strdup (const char *s, const char *pos) char *buf; if (s == NULL) - return (char *)0; + return NULL; size = strlen (s); if ((buf = dbg_malloc (size + 1, pos)) == NULL) - return (char *)0; + return NULL; return strncpy (buf, s, size + 1); } @@ -287,24 +287,24 @@ dump_block_info (struct mem_blk *blk) if (blk == NULL) return; - printf (_("---==== MEMORY BLOCK ====----------------\n")); + puts (_("---==== 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 (_("-----------------------------------------\n")); } void mem_stats (void) { - printf ("\n"); - printf (_("+------------------------------+\n")); - printf (_("| calcurse memory usage report |\n")); - printf (_("+------------------------------+\n")); + 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); - printf ("\n"); + putchar ("\n"); if (mstats.nfree < mstats.nalloc) { diff --git a/src/note.c b/src/note.c new file mode 100644 index 0000000..e5595fc --- /dev/null +++ b/src/note.c @@ -0,0 +1,235 @@ +/* + * Calcurse - text-based organizer + * + * Copyright (c) 2004-2011 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); +}; + +/* Edit a note with an external editor. */ +void +edit_note (char **note, 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); + if ((tmpext = new_tempfile (tmppath, TMPEXTSIZ)) == NULL) + return; + strncat (tmppath, tmpext, BUFSIZ); + 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 (char *note, 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, 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) +{ + HTABLE_HEAD (htp, NOTE_GC_HSIZE, note_gc_hash) 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. */ + HTABLE_GENERATE (htp, note_gc_hash, note_gc_extract_key, note_gc_cmp); + 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 188d92c..6529087 100644 --- a/src/notify.c +++ b/src/notify.c @@ -80,7 +80,8 @@ 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; @@ -111,7 +112,7 @@ notify_bar (void) display_bar = (nbar.show) ? 1 : 0; pthread_mutex_unlock (&nbar.mutex); - return (display_bar); + return display_bar; } /* Initialize the nbar variable used to store notification options. */ @@ -125,16 +126,17 @@ notify_init_vars (void) 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) 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. */ @@ -226,7 +228,7 @@ notify_launch_cmd (void) else if (pid == 0) { /* Child: launch user defined command */ - if (execlp (nbar.shell, nbar.shell, "-c", nbar.cmd, (char *)0) < 0) + if (execlp (nbar.shell, nbar.shell, "-c", nbar.cmd, NULL) < 0) { ERROR_MSG (_("error while launching command")); _exit (1); @@ -272,7 +274,7 @@ notify_update_bar (void) too_long = 1; shrink_len = txt_max_len > 3 ? txt_max_len - 3 : 1; - (void)strncpy (buf, notify_app.txt, shrink_len); + strncpy (buf, notify_app.txt, shrink_len); buf[shrink_len] = '\0'; } time_left = notify_time_left (); @@ -284,7 +286,9 @@ notify_update_bar (void) minutes_left = (time_left - hours_left * HOURINSEC) / MININSEC; pthread_mutex_lock (&nbar.mutex); - if (time_left < nbar.cntdwn && (notify_app.state & APOINT_NOTIFY)) + 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; @@ -301,7 +305,7 @@ notify_update_bar (void) wattroff (notify.win, A_BLINK); if (blinking) - (void)notify_launch_cmd (); + notify_launch_cmd (); pthread_mutex_unlock (&nbar.mutex); } else @@ -359,7 +363,7 @@ notify_main_thread (void *arg) notify_check_next_app (0); } } - pthread_exit ((void *) 0); + pthread_exit (NULL); } /* Fill the given structure with information about next appointment. */ @@ -376,9 +380,9 @@ notify_get_next (struct notify_app *a) 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; } @@ -392,7 +396,7 @@ notify_get_next_bkgd (void) { struct notify_app a; - a.txt = (char *)0; + a.txt = NULL; if (!notify_get_next (&a)) return 0; @@ -421,7 +425,7 @@ 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. */ @@ -433,7 +437,7 @@ notify_thread_app (void *arg) int force = (arg ? 1 : 0); if (!notify_get_next (&tmp_app)) - pthread_exit ((void *)0); + pthread_exit (NULL); if (!tmp_app.got_app) { @@ -455,7 +459,7 @@ notify_thread_app (void *arg) 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. */ @@ -463,7 +467,7 @@ 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); @@ -505,15 +509,15 @@ notify_check_added (char *mesg, long start, char state) 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 (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) { @@ -554,10 +558,11 @@ 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 ()); + 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; @@ -602,7 +607,7 @@ print_option (WINDOW *win, unsigned x, unsigned y, char *name, { char buf[BUFSIZ]; - (void)strncpy (buf, valstr, maxlen - 1); + strncpy (buf, valstr, maxlen - 1); buf[maxlen - 1] = '\0'; mvwprintw (win, y, x_opt, "%s...", buf); } @@ -622,7 +627,7 @@ print_config_options (WINDOW *optwin) const int YOFF = 3; enum - { SHOW, DATE, CLOCK, WARN, CMD, DMON, DMON_LOG, NB_OPT }; + { SHOW, DATE, CLOCK, WARN, CMD, NOTIFY_ALL, DMON, DMON_LOG, NB_OPT }; struct opt_s { @@ -650,6 +655,9 @@ print_config_options (WINDOW *optwin) opt[CMD].name = _("notify-bar_command = "); opt[CMD].desc = _("(Command used to notify user of an upcoming appointment)"); + opt[NOTIFY_ALL].name = _("notify-all = "); + opt[NOTIFY_ALL].desc = _("(Notify all appointments instead of flagged ones only)"); + opt[DMON].name = _("notify-daemon_enable = "); opt[DMON].desc = _("(Run in background to get notifications after exiting)"); @@ -659,19 +667,21 @@ print_config_options (WINDOW *optwin) 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; + 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++) { @@ -719,7 +729,7 @@ notify_config_bar (void) clear (); custom_set_swsiz (&cwin); - (void)snprintf (cwin.label, BUFSIZ, _("notification options")); + strncpy (cwin.label, _("notification options"), BUFSIZ); wins_scrollwin_init (&cwin); wins_show (cwin.win.p, cwin.label); status_mesg (number_str, keys); @@ -753,24 +763,24 @@ notify_config_bar (void) case '2': status_mesg (date_str, ""); pthread_mutex_lock (&nbar.mutex); - (void)strncpy (buf, nbar.datefmt, strlen (nbar.datefmt) + 1); + 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); + 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); + 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); + strncpy (nbar.timefmt, buf, strlen (buf) + 1); pthread_mutex_unlock (&nbar.mutex); } break; @@ -790,19 +800,25 @@ notify_config_bar (void) case '5': status_mesg (cmd_str, ""); pthread_mutex_lock (&nbar.mutex); - (void)strncpy (buf, nbar.cmd, strlen (nbar.cmd) + 1); + 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); + strncpy (nbar.cmd, buf, strlen (buf) + 1); pthread_mutex_unlock (&nbar.mutex); } break; case '6': - dmon.enable = !dmon.enable; + 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; } diff --git a/src/recur.c b/src/recur.c index caa5ec3..f8f04e0 100644 --- a/src/recur.c +++ b/src/recur.c @@ -63,7 +63,7 @@ free_exc_list (llist_t *exc) 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 @@ -93,7 +93,7 @@ exc_dup (llist_t *in, llist_t *exc) } void -recur_event_free_bkp (enum eraseflg flag) +recur_event_free_bkp (void) { if (bkp_cut_recur_event.mesg) { @@ -106,11 +106,11 @@ recur_event_free_bkp (enum eraseflg flag) bkp_cut_recur_event.rpt = 0; } free_exc_list (&bkp_cut_recur_event.exc); - erase_note (&bkp_cut_recur_event.note, flag); + erase_note (&bkp_cut_recur_event.note); } void -recur_apoint_free_bkp (enum eraseflg flag) +recur_apoint_free_bkp (void) { if (bkp_cut_recur_apoint.mesg) { @@ -123,7 +123,7 @@ recur_apoint_free_bkp (enum eraseflg flag) bkp_cut_recur_apoint.rpt = 0; } free_exc_list (&bkp_cut_recur_apoint.exc); - erase_note (&bkp_cut_recur_apoint.note, flag); + erase_note (&bkp_cut_recur_apoint.note); } static void @@ -214,13 +214,13 @@ recur_event_llist_free (void) static int 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) { - 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 */ @@ -310,7 +310,7 @@ recur_def2char (enum recur_type define) return 0; } - return (recur_char); + return recur_char; } /* @@ -340,7 +340,7 @@ recur_char2def (char type) EXIT (_("unknown character")); return 0; } - return (recur_def); + return recur_def; } /* Write days for which recurrent items should not be repeated. */ @@ -360,7 +360,7 @@ recur_write_exc (llist_t *lexc, FILE *f) 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); + fprintf (f, " !%02u/%02u/%04u", st_mon, st_day, st_year); } } @@ -374,7 +374,7 @@ recur_apoint_scan (FILE *f, struct tm start, struct tm end, char type, time_t tstart, tend, tuntil; /* Read the appointment description */ - (void)fgets (buf, sizeof buf, f); + fgets (buf, sizeof buf, f); nl = strchr (buf, '\n'); if (nl) { @@ -406,8 +406,8 @@ recur_apoint_scan (FILE *f, struct tm start, struct tm end, char type, 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)); + return recur_apoint_new (buf, note, tstart, tend - tstart, state, + recur_char2def(type), freq, tuntil, exc); } /* Load the recursive events from file */ @@ -419,13 +419,13 @@ recur_event_scan (FILE *f, struct tm start, int id, char type, int freq, time_t tstart, tuntil; /* Read the event description */ - (void)fgets (buf, sizeof buf, f); + fgets (buf, sizeof buf, f); nl = strchr (buf, '\n'); if (nl) { *nl = '\0'; } - start.tm_hour = until.tm_hour = 12; + 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; @@ -445,12 +445,12 @@ recur_event_scan (FILE *f, struct tm start, int id, char type, int freq, EXIT_IF (tstart == -1 || tuntil == -1, _("date error in event")); - return recur_event_new (buf, note, tstart, id, recur_char2def (type), - freq, tuntil, exc); + return recur_event_new (buf, note, tstart, id, recur_char2def(type), freq, + tuntil, exc); } /* Writting of a recursive appointment into file. */ -static void +void recur_apoint_write (struct recur_apoint *o, FILE *f) { struct tm *lt; @@ -458,41 +458,39 @@ recur_apoint_write (struct recur_apoint *o, FILE *f) 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); + 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); + 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)); + 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); + 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, "} "); + 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 +void recur_event_write (struct recur_event *o, FILE *f) { struct tm *lt; @@ -508,9 +506,8 @@ recur_event_write (struct recur_event *o, FILE *f) 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)); + 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 { @@ -518,16 +515,15 @@ recur_event_write (struct recur_event *o, FILE *f) 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); + 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, "} "); + 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. */ @@ -553,9 +549,9 @@ recur_save_data (FILE *f) /* - * 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 \ @@ -586,13 +582,6 @@ diff_days (struct tm lt_start, struct tm lt_end) 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) @@ -618,12 +607,12 @@ diff_years (struct tm lt_start, struct tm lt_end) static int exc_inday (struct excp *exc, long day_start) { - return (exc->st >= day_start && exc->st < day_start + DAYINSEC); + return exc->st >= day_start && exc->st < day_start + DAYINSEC; } /* - * 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 +620,135 @@ 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; - t = day_start; - lt_day = *localtime (&t); - - if (LLIST_FIND_FIRST (item_exc, day_start, exc_inday)) + if (day_start < item_start - DAYINSEC + 1) return 0; - if (rpt_until == 0) /* we have an endless recurrent item */ - rpt_until = day_end; + if (rpt_until != 0 && day_start >= rpt_until + item_dur) + return 0; - if (item_start > day_end || rpt_until < day_start) - return (0); + t = day_start; + lt_day = *localtime (&t); 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, 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; + 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: - 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; + 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, 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; + 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, lt_day); - if (diff % rpt_freq != 0) - return (0); - lt_item.tm_year = lt_day.tm_year; + 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")); } - 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); + 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 && t > rpt_until) + return 0; + + lt_item_day = *localtime (&t); + diff = diff_days (lt_item_day, lt_day); + + 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); + } + + return 1; + } else - return (0); + 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_event_find_occurrence (struct recur_event *rev, long day_start, + unsigned *occurrence) +{ + 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_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->exc, rapt->rpt->type, - rapt->rpt->freq, rapt->rpt->until, 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); } /* @@ -740,12 +772,12 @@ recur_event_erase (long start, unsigned num, unsigned delete_whole, switch (flag) { case ERASE_FORCE_ONLY_NOTE: - erase_note (&rev->note, flag); + erase_note (&rev->note); break; case ERASE_CUT: - recur_event_free_bkp (ERASE_FORCE); + recur_event_free_bkp (); recur_event_dup (rev, &bkp_cut_recur_event); - erase_note (&rev->note, ERASE_FORCE_KEEP_NOTE); + erase_note (&rev->note); /* FALLTHROUGH */ default: LLIST_REMOVE (&recur_elist, i); @@ -756,8 +788,6 @@ recur_event_erase (long start, unsigned num, unsigned delete_whole, 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; } @@ -791,12 +821,12 @@ recur_apoint_erase (long start, unsigned num, unsigned delete_whole, switch (flag) { case ERASE_FORCE_ONLY_NOTE: - erase_note (&rapt->note, flag); + erase_note (&rapt->note); break; case ERASE_CUT: - recur_apoint_free_bkp (ERASE_FORCE); + recur_apoint_free_bkp (); recur_apoint_dup (rapt, &bkp_cut_recur_apoint); - erase_note (&rapt->note, ERASE_FORCE_KEEP_NOTE); + erase_note (&rapt->note); /* FALLTHROUGH */ default: LLIST_TS_REMOVE (&recur_alist_p, i); @@ -807,8 +837,6 @@ recur_apoint_erase (long start, unsigned num, unsigned delete_whole, 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); @@ -867,7 +895,7 @@ recur_repeat_item (struct conf *conf) if (p->type != APPT && p->type != EVNT) { status_mesg (wrong_type_1, wrong_type_2); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); return; } @@ -896,7 +924,7 @@ recur_repeat_item (struct conf *conf) if (freq == 0) { status_mesg (mesg_wrong_freq, wrong_type_2); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); } user_input[0] = '\0'; } @@ -906,8 +934,8 @@ recur_repeat_item (struct conf *conf) while (!date_entered) { - (void)snprintf (outstr, BUFSIZ, mesg_until_1, - DATEFMT_DESC (conf->input_datefmt)); + 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) { @@ -930,7 +958,7 @@ recur_repeat_item (struct conf *conf) if (until < p->start) { status_mesg (mesg_older, wrong_type_2); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); date_entered = 0; } else @@ -940,10 +968,10 @@ recur_repeat_item (struct conf *conf) } else { - (void)snprintf (outstr, BUFSIZ, mesg_wrong_2, - DATEFMT_DESC (conf->input_datefmt)); + snprintf (outstr, BUFSIZ, mesg_wrong_2, + DATEFMT_DESC (conf->input_datefmt)); status_mesg (mesg_wrong_1, _(outstr)); - (void)wgetch (win[STA].p); + wgetch (win[STA].p); date_entered = 0; } } @@ -955,8 +983,8 @@ recur_repeat_item (struct conf *conf) 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); + recur_event_new (p->mesg, p->note, p->start, p->evnt_id, type, freq, + until, NULL); } else if (p->type == APPT) { @@ -970,7 +998,7 @@ recur_repeat_item (struct conf *conf) EXIT (_("wrong item type")); /* NOTREACHED */ } - day_erase_item (date, item_nb, ERASE_FORCE_KEEP_NOTE); + day_erase_item (date, item_nb, ERASE_FORCE); } /* @@ -986,13 +1014,13 @@ recur_exc_scan (llist_t *lexc, FILE *data_file) LLIST_INIT (lexc); while ((c = getc (data_file)) == '!') { - (void)ungetc (c, data_file); + 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_hour = 0; day.tm_min = day.tm_sec = 0; day.tm_isdst = -1; day.tm_year -= 1900; @@ -1006,7 +1034,7 @@ recur_exc_scan (llist_t *lexc, FILE *data_file) static int recur_apoint_starts_before (struct recur_apoint *rapt, long time) { - return (rapt->start < time); + return rapt->start < time; } /* @@ -1017,15 +1045,15 @@ struct notify_app * recur_apoint_check_next (struct notify_app *app, long start, long day) { llist_item_t *i; - long real_recur_start_time; + 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); - real_recur_start_time = recur_apoint_inday(rapt, day); - if (real_recur_start_time > start) + 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); @@ -1035,7 +1063,7 @@ recur_apoint_check_next (struct notify_app *app, long start, long day) } LLIST_TS_UNLOCK (&recur_alist_p); - return (app); + return app; } /* Returns a structure containing the selected recurrent appointment. */ @@ -1093,7 +1121,7 @@ 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; @@ -1105,13 +1133,12 @@ recur_event_paste_item (void) 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); + 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 @@ -1134,16 +1161,15 @@ recur_apoint_paste_item (void) 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); - 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..cc11dd7 --- /dev/null +++ b/src/sha1.c @@ -0,0 +1,241 @@ +/* + * Calcurse - text-based organizer + * + * Copyright (c) 2004-2011 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); + +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..2e28bd4 --- /dev/null +++ b/src/sha1.h @@ -0,0 +1,57 @@ +/* + * Calcurse - text-based organizer + * + * Copyright (c) 2004-2011 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 *); @@ -61,7 +61,7 @@ generic_hdlr (int sig) case SIGWINCH: resize = 1; clearok (curscr, TRUE); - (void)ungetch (KEY_RESIZE); + ungetch (KEY_RESIZE); break; case SIGTERM: if (unlink (path_cpid) != 0) @@ -83,7 +83,7 @@ sigs_set_hdlr (int sig, void (*handler)(int)) sigemptyset (&sa.sa_mask); sa.sa_handler = handler; sa.sa_flags = 0; - if (sigaction (sig, &sa, (struct sigaction *)0) == -1) + if (sigaction (sig, &sa, NULL) == -1) { ERROR_MSG (_("Error setting signal #%d : %s\n"), sig, strerror (errno)); @@ -61,29 +61,29 @@ todo_hilt_set (int highlighted) } void -todo_hilt_decrease (void) +todo_hilt_decrease (int n) { - hilt--; + hilt -= n; } void -todo_hilt_increase (void) +todo_hilt_increase (int n) { - hilt++; + hilt += n; } /* Return which todo is highlighted. */ int todo_hilt (void) { - return (hilt); + return hilt; } /* Return the number of todos. */ int todo_nb (void) { - return (todos); + return todos; } /* Set the number of todos. */ @@ -101,15 +101,15 @@ todo_set_first (int nb) } void -todo_first_increase (void) +todo_first_increase (int n) { - first++; + first += n; } void -todo_first_decrease (void) +todo_first_decrease (int n) { - first--; + first -= n; } /* @@ -119,14 +119,14 @@ todo_first_decrease (void) int todo_hilt_pos (void) { - return (hilt - first); + return hilt - first; } /* Return the last visited todo. */ char * todo_saved_mesg (void) { - return (msgsav); + return msgsav; } /* Request user to enter a new todo item. */ @@ -162,7 +162,7 @@ todo_cmp_id (struct todo *a, struct todo *b) 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); } /* @@ -183,6 +183,15 @@ todo_add (char *mesg, int id, char *note) 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) @@ -195,12 +204,12 @@ todo_delete_note_bynum (unsigned num) if (!todo->note) EXIT (_("no note attached")); - erase_note (&todo->note, ERASE_FORCE_ONLY_NOTE); + erase_note (&todo->note); } /* Delete an item from the todo linked list. */ static void -todo_delete_bynum (unsigned num, enum eraseflg flag) +todo_delete_bynum (unsigned num) { llist_item_t *i = LLIST_NTH (&todolist, num); @@ -210,7 +219,7 @@ todo_delete_bynum (unsigned num, enum eraseflg flag) LLIST_REMOVE (&todolist, i); mem_free (todo->mesg); - erase_note (&todo->note, flag); + erase_note (&todo->note); mem_free (todo); } @@ -279,7 +288,7 @@ todo_delete (struct conf *conf) switch (answer) { case 't': - todo_delete_bynum (hilt - 1, ERASE_FORCE); + todo_delete_bynum (hilt - 1); todos--; if (hilt > 1) hilt--; @@ -325,14 +334,14 @@ todo_chg_priority (int action) struct todo *backup; char backup_mesg[BUFSIZ]; int backup_id; - char backup_note[NOTESIZ + 1]; + char backup_note[MAX_NOTESIZ + 1]; int do_chg = 1; backup = todo_get_item (hilt); - (void)strncpy (backup_mesg, backup->mesg, strlen (backup->mesg) + 1); + 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) @@ -349,7 +358,7 @@ todo_chg_priority (int action) } if (do_chg) { - todo_delete_bynum (hilt - 1, ERASE_FORCE_KEEP_NOTE); + todo_delete_bynum (hilt - 1); backup = todo_add (backup_mesg, backup_id, backup_note); hilt = todo_get_position (backup); } @@ -369,28 +378,37 @@ todo_edit_item (void) /* Display todo items in the corresponding panel. */ static void -display_todo_item (int incolor, char *msg, int prio, int note, int len, int y, +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); else - snprintf (priostr, sizeof priostr, "X"); + strncpy (priostr, "X", sizeof priostr); if (incolor == 0) custom_apply_attr (w, ATTR_HIGHEST); - if (strlen (msg) < len) + if (utf8_strwidth (msg) < width) mvwprintw (w, y, x, "%s%c %s", priostr, ch_note, msg); else { - (void)strncpy (buf, msg, len - 1); - buf[len - 1] = '\0'; + 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) @@ -419,7 +437,7 @@ todo_update_panel (int which_pan) struct todo *todo = LLIST_TS_GET_DATA (i); num_todo++; t_realpos = num_todo - first; - incolor = num_todo - hilt; + incolor = (which_pan == TOD) ? num_todo - hilt : num_todo; if (incolor == 0) msgsav = todo->mesg; if (t_realpos >= 0 && t_realpos < max_items) @@ -453,44 +471,52 @@ todo_update_panel (int which_pan) void todo_edit_note (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) { - 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] = ""; + 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, cmd))) + { + 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) { mem_free (todo->mesg); - erase_note (&todo->note, ERASE_FORCE_KEEP_NOTE); + erase_note (&todo->note); mem_free (todo); } diff --git a/src/utf8.c b/src/utf8.c new file mode 100644 index 0000000..1bb199c --- /dev/null +++ b/src/utf8.c @@ -0,0 +1,344 @@ +/* + * Calcurse - text-based organizer + * + * Copyright (c) 2004-2011 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 b165111..3c7f595 100644 --- a/src/utils.c +++ b/src/utils.c @@ -42,6 +42,8 @@ #include <ctype.h> #include <sys/types.h> #include <errno.h> +#include <fcntl.h> +#include <sys/wait.h> #include "calcurse.h" @@ -87,13 +89,13 @@ free_user_data (void) { day_free_list (); event_llist_free (); - event_free_bkp (ERASE_FORCE); + event_free_bkp (); apoint_llist_free (); - apoint_free_bkp (ERASE_FORCE); + apoint_free_bkp (); recur_apoint_llist_free (); recur_event_llist_free (); - recur_apoint_free_bkp (ERASE_FORCE); - recur_event_free_bkp (ERASE_FORCE); + recur_apoint_free_bkp (); + recur_event_free_bkp (); todo_free_list (); notify_free_app (); } @@ -113,7 +115,7 @@ fatalbox (const char *errmsg) if (errmsg == NULL) return; - (void)strncpy (msg, errmsg, MSGLEN); + strncpy (msg, errmsg, MSGLEN); errwin = newwin (WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2); custom_apply_attr (errwin, ATTR_HIGHEST); box (errwin, 0, 0); @@ -122,7 +124,7 @@ fatalbox (const char *errmsg) mvwprintw (errwin, 5, (WINCOL - strlen (msg)) / 2, "%s", msg); custom_remove_attr (errwin, ATTR_HIGHEST); wins_wrefresh (errwin); - (void)wgetch (errwin); + wgetch (errwin); delwin (errwin); wins_doupdate (); } @@ -140,7 +142,7 @@ warnbox (const char *msg) if (msg == NULL) return; - (void)strncpy (displmsg, msg, MSGLEN); + strncpy (displmsg, msg, MSGLEN); warnwin = newwin (WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2); custom_apply_attr (warnwin, ATTR_HIGHEST); box (warnwin, 0, 0); @@ -148,7 +150,7 @@ warnbox (const char *msg) mvwprintw (warnwin, 5, (WINCOL - strlen (displmsg)) / 2, "%s", displmsg); custom_remove_attr (warnwin, ATTR_HIGHEST); wins_wrefresh (warnwin); - (void)wgetch (warnwin); + wgetch (warnwin); delwin (warnwin); wins_doupdate (); } @@ -199,7 +201,7 @@ popup (int pop_row, int pop_col, int pop_y, int pop_x, char *title, char *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); + 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", @@ -230,189 +232,6 @@ print_in_middle (WINDOW *win, int starty, int startx, int width, char *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; -} - /* checks if a string is only made of digits */ int is_all_digit (char *string) @@ -430,8 +249,8 @@ is_all_digit (char *string) 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 @@ -474,7 +293,7 @@ date_sec2date_str (long sec, char *datefmt) char *datestr = (char *) mem_calloc (BUFSIZ, sizeof (char)); if (sec == 0) - (void)snprintf (datestr, BUFSIZ, "0"); + strncpy (datestr, "0", BUFSIZ); else { lt = localtime ((time_t *)&sec); @@ -529,7 +348,7 @@ update_time_in_date (long date, unsigned hr, unsigned mn) new_date = mktime (lt); EXIT_IF (new_date == -1, _("error in mktime")); - return (new_date); + return new_date; } /* @@ -558,44 +377,13 @@ get_sec_date (struct date date) date.yyyy = atoi (current_year); } long_date = date2sec (date, 0, 0); - return (long_date); + return long_date; } 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; } /* @@ -631,7 +419,7 @@ item_in_popup (char *saved_a_start, char *saved_a_end, char *msg, 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); + popup_win = popup (winl, winw, 1, 2, pop_title, NULL, 1); if (strncmp (pop_title, _("Appointment"), 11) == 0) { mvwprintw (popup_win, margin_top, margin_left, "- %s -> %s", @@ -641,7 +429,7 @@ item_in_popup (char *saved_a_start, char *saved_a_end, char *msg, wmove (win[STA].p, 0, 0); pnoutrefresh (pad, 0, 0, margin_top + 2, margin_left, padl, winw); wins_doupdate (); - (void)wgetch (popup_win); + wgetch (popup_win); delwin (pad); delwin (popup_win); } @@ -662,7 +450,7 @@ get_today (void) day.yyyy = lt->tm_year + 1900; current_day = date2sec (day, 0, 0); - return (current_day); + return current_day; } /* Returns the current time in seconds. */ @@ -678,7 +466,7 @@ nowstr (void) static char buf[BUFSIZ]; 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; } @@ -696,7 +484,7 @@ mystrtol (const char *str) if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) EXIT (_("out of range")); - return (lval); + return lval; } /* Print the given option value with appropriate color. */ @@ -753,13 +541,13 @@ new_tempfile (const char *prefix, int trailing_len) FILE *file; if (prefix == NULL) - return (NULL); + return NULL; prefix_len = strlen (prefix); if (prefix_len + trailing_len >= BUFSIZ) - return (NULL); + return NULL; memcpy (fullname, prefix, prefix_len); - (void)memset (fullname + prefix_len, 'X', trailing_len); + memset (fullname + prefix_len, 'X', trailing_len); fullname[prefix_len + trailing_len] = '\0'; if ((fd = mkstemp (fullname)) == -1 || (file = fdopen (fd, "w+")) == NULL) { @@ -769,31 +557,13 @@ new_tempfile (const char *prefix, int trailing_len) close (fd); } ERROR_MSG (_("temporary file \"%s\" could not be created"), fullname); - return (char *)0; + return NULL; } 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]; - - 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; -} - /* * Convert a string containing a date into three integers containing the year, * month and day. @@ -807,11 +577,11 @@ 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; + const char sep = (datefmt == DATEFMT_ISO) ? '-' : '/'; + const char *p; int in[3] = {0, 0, 0}, n = 0; int d, m, y; @@ -888,6 +658,168 @@ parse_date (char *date_string, enum datefmt datefmt, int *year, int *month, return 1; } +/* + * 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)". + * + * Note that this function performs an additional range check on each token to + * ensure we do not accept semantically invalid strings such as "42:23". + * + * 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') + { + if (in >= DAYINHOURS) + return 0; + dur += in * HOURINMIN; + state = STATE_DDHHMM_MM; + } + else if (*p == 'm') + { + if (in >= HOURINMIN) + return 0; + dur += in; + state = STATE_DONE; + } + else + return 0; + break; + case STATE_DDHHMM_HH: + if (*p == 'h') + { + if (in >= DAYINHOURS) + return 0; + dur += in * HOURINMIN; + state = STATE_DDHHMM_MM; + } + else if (*p == 'm') + { + if (in >= HOURINMIN) + return 0; + dur += in; + state = STATE_DONE; + } + else + return 0; + break; + case STATE_DDHHMM_MM: + if (*p == 'm') + { + if (in >= HOURINMIN) + return 0; + 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) { @@ -916,3 +848,108 @@ psleep (unsigned secs) 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, 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; +} + +/* Execute an external program in a shell. */ +int +shell_exec (int *pfdin, int *pfdout, char *cmd) +{ + char *arg[] = { "/bin/sh", "-c", cmd, NULL }; + return fork_exec (pfdin, pfdout, *arg, arg); +} + +/* 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) +{ + fflush (stdout); + fputs (_("Press any key to continue..."), stdout); + fflush (stdout); + fgetc (stdin); + fflush (stdin); + fputs ("\r\n", stdout); +} @@ -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). @@ -120,10 +123,11 @@ vars_init (struct conf *conf) conf->confirm_quit = 1; conf->confirm_delete = 1; conf->auto_save = 1; + conf->auto_gc = 0; conf->periodic_save = 0; conf->skip_system_dialogs = 0; conf->skip_progress_bar = 0; - (void)strncpy (conf->output_datefmt, "%D", 3); + strncpy (conf->output_datefmt, "%D", 3); conf->input_datefmt = 1; /* Default external editor and pager */ @@ -75,7 +75,7 @@ screen_acquire (void) static void screen_release (void) { - (void)pthread_mutex_unlock (&screen_mutex); + pthread_mutex_unlock (&screen_mutex); } int @@ -201,7 +201,7 @@ wins_slctd_init (void) enum win wins_slctd (void) { - return (slctd_win); + return slctd_win; } /* Sets the selected window. */ @@ -227,17 +227,17 @@ 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")); + strncpy (label, _("Calendar"), BUFSIZ); wins_show (win[CAL].p, label); win[APP].p = newwin (win[APP].h, win[APP].w, win[APP].y, win[APP].x); - (void)snprintf (label, BUFSIZ, _("Appointments")); + strncpy (label, _("Appointments"), BUFSIZ); wins_show (win[APP].p, label); apad.width = win[APP].w - 3; 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")); + strncpy (label, _("ToDo"), BUFSIZ); wins_show (win[TOD].p, label); /* Enable function keys (i.e. arrow keys) in those windows */ @@ -539,37 +539,40 @@ border_nocolor (WINDOW *window) } void -wins_update_border (void) +wins_update_border (int flags) { - switch (slctd_win) + if (flags & FLAG_CAL) { - 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 */ + 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 (void) +wins_update_panels (int flags) { - apoint_update_panel (slctd_win); - todo_update_panel (slctd_win); - calendar_update_panel (&win[CAL]); + 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]); } /* @@ -577,12 +580,13 @@ wins_update_panels (void) * selected window. */ void -wins_update (void) +wins_update (int flags) { - wins_update_border (); - wins_update_panels (); - wins_status_bar (); - if (notify_bar ()) + 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 (); @@ -596,36 +600,26 @@ wins_reset (void) wins_refresh (); curs_set (0); wins_reinit (); - wins_update (); + wins_update (FLAG_ALL); } -/* - * While inside interactive mode, launch the external command cmd on the given - * file. - */ +/* Prepare windows for the execution of an external command. */ void -wins_launch_external (const char *file, const char *cmd) +wins_prepare_external (void) { - 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); + endwin (); +} + +/* Restore windows when returning from an external command. */ +void +wins_unprepare_external (void) +{ reset_prog_mode (); clearok (curscr, TRUE); curs_set (0); @@ -633,12 +627,27 @@ wins_launch_external (const char *file, const char *cmd) wins_refresh (); if (notify_bar ()) notify_start_main_thread (); - mem_free (p); +} + +/* + * While inside interactive mode, launch the external command cmd on the given + * file. + */ +void +wins_launch_external (char *file, char *cmd) +{ + char *arg[] = { cmd, file, NULL }; + int pid; + + wins_prepare_external (); + if ((pid = fork_exec (NULL, NULL, cmd, 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 NB_APP_CMDS 32 /* same thing while in appointment view */ +#define NB_TOD_CMDS 31 /* 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 */ @@ -690,6 +699,7 @@ wins_status_bar (void) 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}; @@ -704,13 +714,14 @@ wins_status_bar (void) &gnday, &gpday, &gnweek, &gpweek, &draw, &othr, &today, &conf, &othr, /* appointment keys */ &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, + &pipe, &othr, &draw, &rept, &flag, &enote, &vnote, &up, &down, &gnday, + &gpday, &gnweek, &gpweek, &othr, &togo, &today, &conf, &appt, &todo, &cut, + &paste, &othr, /* todo keys */ &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, &othr, &flag, &rprio, &lprio, &enote, &vnote, &up, &down, &gnday, + &gpday, &gnweek, &gpweek, &othr, &togo, &today, &conf, &appt, &todo, &draw, + &othr }; /* Drawing the keybinding with attribute and label without. */ |