diff options
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | doc/manual.txt | 3 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/calcurse.c | 7 | ||||
-rw-r--r-- | src/calcurse.h | 33 | ||||
-rw-r--r-- | src/day.c | 76 | ||||
-rw-r--r-- | src/getstring.c | 299 | ||||
-rw-r--r-- | src/help.c | 13 | ||||
-rw-r--r-- | src/io.c | 5 | ||||
-rw-r--r-- | src/keys.c | 11 | ||||
-rw-r--r-- | src/recur.c | 4 | ||||
-rw-r--r-- | src/todo.c | 57 | ||||
-rw-r--r-- | src/utf8.c | 344 | ||||
-rw-r--r-- | src/utils.c | 290 | ||||
-rw-r--r-- | src/wins.c | 61 |
15 files changed, 969 insertions, 239 deletions
@@ -9,9 +9,6 @@ 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 diff --git a/doc/manual.txt b/doc/manual.txt index c0a992d..6bf7637 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 diff --git a/src/Makefile.am b/src/Makefile.am index faacf46..8fff8e3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,6 +14,7 @@ calcurse_SOURCES = \ custom.c \ day.c \ event.c \ + getstring.c \ help.c \ io.c \ keys.c \ @@ -22,6 +23,7 @@ calcurse_SOURCES = \ recur.c \ sigs.c \ todo.c \ + utf8.c \ utils.c \ vars.c \ wins.c \ diff --git a/src/calcurse.c b/src/calcurse.c index 662f185..0ae7e9a 100644 --- a/src/calcurse.c +++ b/src/calcurse.c @@ -368,6 +368,13 @@ main (int argc, char **argv) do_storage = 1; 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_pipe_item (); + break; + case KEY_RAISE_PRIORITY: case KEY_LOWER_PRIORITY: if (wins_slctd () == TOD && todo_hilt () != 0) diff --git a/src/calcurse.h b/src/calcurse.h index e3822ef..b94da61 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -200,6 +200,15 @@ #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)) @@ -392,6 +401,7 @@ enum key { KEY_DEL_ITEM, KEY_EDIT_ITEM, KEY_VIEW_ITEM, + KEY_PIPE_ITEM, KEY_FLAG_ITEM, KEY_REPEAT_ITEM, KEY_EDIT_NOTE, @@ -628,6 +638,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); @@ -650,6 +661,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 *); @@ -778,6 +793,8 @@ 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_apoint_inday(struct recur_apoint *, long); @@ -814,6 +831,7 @@ 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); @@ -821,9 +839,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); @@ -833,8 +856,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); @@ -862,6 +883,10 @@ int parse_date (char *, enum datefmt, int *, int *, int *, 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; @@ -915,7 +940,9 @@ void wins_update_border (void); void wins_update_panels (void); void wins_update (void); void wins_reset (void); -void wins_launch_external (const char *, const char *); +void wins_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); @@ -347,14 +347,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 +363,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) @@ -1089,3 +1098,58 @@ day_view_note (char *pager) (void)snprintf (fullname, BUFSIZ, "%s%s", path_notes, p->note); wins_launch_external (fullname, 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; + struct recur_apoint *ra; + struct apoint *a; + struct recur_event *re; + struct event *e; + + status_mesg (_("Pipe item to external command:"), ""); + if (getstring (win[STA].p, cmd, BUFSIZ, 0, 1) != GETSTRING_VALID) + return; + + wins_prepare_external (); + if ((pid = shell_exec (NULL, &pout, 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 (); +} diff --git a/src/getstring.c b/src/getstring.c new file mode 100644 index 0000000..8633ef3 --- /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) +{ + printf ("\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); + (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; +} @@ -56,6 +56,7 @@ typedef enum HELP_EXPORT, HELP_DISPLACEMENT, HELP_VIEW, + HELP_PIPE, HELP_TAB, HELP_GOTO, HELP_DELETE, @@ -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; @@ -451,6 +456,14 @@ help_screen (void) "Calcurse screen."), keys_action_firstkey (KEY_VIEW_ITEM)); + hscr[HELP_PIPE].title = _("Pipe\n"); + (void)snprintf (hscr[HELP_PIPE].text, HELPTEXTSIZ, + _("Pipe the selected item to an external program.\n" + "\nPress the '%s' key to pipe the currently selected appointment or\n" + "todo entry to an external program.\n" + "\nYou will be driven back to calcurse as soon as the program exits.\n"), + keys_action_firstkey (KEY_PIPE_ITEM)); + hscr[HELP_TAB].title = _("Tab\n"); (void)snprintf (hscr[HELP_TAB].text, HELPTEXTSIZ, _("Switch between panels.\n" @@ -1024,10 +1024,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__); @@ -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"}, @@ -567,6 +568,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] = diff --git a/src/recur.c b/src/recur.c index 430e543..b757400 100644 --- a/src/recur.c +++ b/src/recur.c @@ -450,7 +450,7 @@ recur_event_scan (FILE *f, struct tm start, int id, char type, int freq, } /* Writting of a recursive appointment into file. */ -static void +void recur_apoint_write (struct recur_apoint *o, FILE *f) { struct tm *lt; @@ -492,7 +492,7 @@ recur_apoint_write (struct recur_apoint *o, FILE *f) } /* Writting of a recursive event into file. */ -static void +void recur_event_write (struct recur_event *o, FILE *f) { struct tm *lt; @@ -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) + (void)fprintf (f, "[%d]>%s %s\n", todo->id, todo->note, todo->mesg); + else + (void)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) @@ -369,12 +378,13 @@ 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) ? '>' : '.'; @@ -385,12 +395,20 @@ display_todo_item (int incolor, char *msg, int prio, int note, int len, int y, 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) @@ -486,6 +504,35 @@ todo_view_note (char *pager) wins_launch_external (fullname, pager); } +/* 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; + + 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) { 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..949b1b7 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" @@ -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) @@ -916,3 +735,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); +} @@ -599,33 +599,23 @@ wins_reset (void) wins_update (); } -/* - * 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 +623,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 +695,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 +710,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. */ |