"Fossies" - the Fresh Open Source Software Archive

Member "calcurse-4.5.1/src/getstring.c" (7 Jun 2019, 7652 Bytes) of package /linux/privat/calcurse-4.5.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "getstring.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 4.3.0_vs_4.4.0.

    1 /*
    2  * Calcurse - text-based organizer
    3  *
    4  * Copyright (c) 2004-2017 calcurse Development Team <misc@calcurse.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  *
   11  *      - Redistributions of source code must retain the above
   12  *        copyright notice, this list of conditions and the
   13  *        following disclaimer.
   14  *
   15  *      - Redistributions in binary form must reproduce the above
   16  *        copyright notice, this list of conditions and the
   17  *        following disclaimer in the documentation and/or other
   18  *        materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  *
   32  * Send your feedback or comments to : misc@calcurse.org
   33  * Calcurse home page : http://calcurse.org
   34  *
   35  */
   36 
   37 #include "calcurse.h"
   38 
   39 struct getstr_charinfo {
   40     unsigned int offset, dpyoff;
   41 };
   42 
   43 struct getstr_status {
   44     char *s;
   45     struct getstr_charinfo *ci;
   46     int pos, len;
   47     int scrpos;
   48 };
   49 
   50 /* Print the string at the desired position. */
   51 static void getstr_print(WINDOW * win, int x, int y,
   52              struct getstr_status *st)
   53 {
   54     char c = 0;
   55 
   56     /* print string */
   57     mvwaddnstr(win, y, x, &st->s[st->ci[st->scrpos].offset], -1);
   58     wclrtoeol(win);
   59 
   60     /* print scrolling indicator */
   61     if (st->scrpos > 0 && st->ci[st->len].dpyoff -
   62         st->ci[st->scrpos].dpyoff > col - 2)
   63         c = '*';
   64     else if (st->scrpos > 0)
   65         c = '<';
   66     else if (st->ci[st->len].dpyoff - st->ci[st->scrpos].dpyoff >
   67          col - 2)
   68         c = '>';
   69     mvwprintw(win, y, col - 2, " %c", c);
   70 
   71     /* print cursor */
   72     wmove(win, y, st->ci[st->pos].dpyoff - st->ci[st->scrpos].dpyoff);
   73     wchgat(win, 1, A_REVERSE, (colorize ? COLR_CUSTOM : 0), NULL);
   74 }
   75 
   76 /* Delete a character at the given position in string. */
   77 static void getstr_del_char(struct getstr_status *st)
   78 {
   79     char *str = st->s + st->ci[st->pos].offset;
   80     int cl = st->ci[st->pos + 1].offset - st->ci[st->pos].offset;
   81     int cw = st->ci[st->pos + 1].dpyoff - st->ci[st->pos].dpyoff;
   82     int i;
   83 
   84     memmove(str, str + cl, strlen(str) + 1);
   85 
   86     st->len--;
   87     for (i = st->pos; i <= st->len; i++) {
   88         st->ci[i].offset = st->ci[i + 1].offset - cl;
   89         st->ci[i].dpyoff = st->ci[i + 1].dpyoff - cw;
   90     }
   91 }
   92 
   93 /* Add a character at the given position in string. */
   94 static void getstr_ins_char(struct getstr_status *st, char *c)
   95 {
   96     char *str = st->s + st->ci[st->pos].offset;
   97     int cl = UTF8_LENGTH(c[0]);
   98     int cw = utf8_width(c);
   99     int i;
  100 
  101     memmove(str + cl, str, strlen(str) + 1);
  102     for (i = 0; i < cl; i++, str++)
  103         *str = c[i];
  104 
  105     for (i = st->len; i >= st->pos; i--) {
  106         st->ci[i + 1].offset = st->ci[i].offset + cl;
  107         st->ci[i + 1].dpyoff = st->ci[i].dpyoff + cw;
  108     }
  109     st->len++;
  110 }
  111 
  112 static void bell(void)
  113 {
  114     putchar('\a');
  115 }
  116 
  117 /* Initialize getstring data structure. */
  118 static void
  119 getstr_init(struct getstr_status *st, char *str,
  120         struct getstr_charinfo *ci)
  121 {
  122     int width;
  123 
  124     st->s = str;
  125     st->ci = ci;
  126 
  127     st->len = width = 0;
  128     while (*str) {
  129         st->ci[st->len].offset = str - st->s;
  130         st->ci[st->len].dpyoff = width;
  131 
  132         st->len++;
  133         width += utf8_width(str);
  134         str += UTF8_LENGTH(*str);
  135     }
  136     st->ci[st->len].offset = str - st->s;
  137     st->ci[st->len].dpyoff = width;
  138 
  139     st->pos = st->len;
  140     st->scrpos = 0;
  141 }
  142 
  143 /* Scroll left/right if the cursor moves outside the window range. */
  144 static void getstr_fixscr(struct getstr_status *st)
  145 {
  146     const int pgsize = col / 3;
  147     int pgskip;
  148 
  149     while (st->pos < st->scrpos) {
  150         pgskip = 0;
  151         while (pgskip < pgsize && st->scrpos > 0) {
  152             st->scrpos--;
  153             pgskip +=
  154                 st->ci[st->scrpos + 1].dpyoff -
  155                 st->ci[st->scrpos].dpyoff;
  156         }
  157     }
  158     while (st->ci[st->pos].dpyoff - st->ci[st->scrpos].dpyoff >
  159            col - 2) {
  160         pgskip = 0;
  161         while (pgskip < pgsize && st->scrpos < st->len) {
  162             pgskip +=
  163                 st->ci[st->scrpos + 1].dpyoff -
  164                 st->ci[st->scrpos].dpyoff;
  165             st->scrpos++;
  166         }
  167     }
  168 }
  169 
  170 /*
  171  * Getstring allows to get user input and to print it on a window,
  172  * even if noecho() is on. This function is also used to modify an existing
  173  * text (the variable string can be non-NULL).
  174  * We need to do the echoing manually because of the multi-threading
  175  * environment, otherwise the cursor would move from place to place without
  176  * control.
  177  */
  178 enum getstr getstring(WINDOW * win, char *str, int l, int x, int y)
  179 {
  180     struct getstr_status st;
  181     struct getstr_charinfo ci[l + 1];
  182 
  183     int ch, k;
  184     char c[UTF8_MAXLEN];
  185 
  186     getstr_init(&st, str, ci);
  187     custom_apply_attr(win, ATTR_HIGHEST);
  188 
  189     for (;;) {
  190         getstr_fixscr(&st);
  191         getstr_print(win, x, y, &st);
  192         wins_doupdate();
  193 
  194         ch = wgetch(win);
  195         if ((ch == '\n') || (ch == KEY_ENTER))
  196             break;
  197         switch (ch) {
  198         case KEY_BACKSPACE: /* delete one character */
  199         case 127:
  200         case CTRL('H'):
  201             if (st.pos > 0) {
  202                 st.pos--;
  203                 getstr_del_char(&st);
  204             } else {
  205                 bell();
  206             }
  207             break;
  208         case KEY_DC:
  209         case CTRL('D'): /* delete next character */
  210             if (st.pos < st.len)
  211                 getstr_del_char(&st);
  212             else
  213                 bell();
  214             break;
  215         case CTRL('W'): /* delete a word */
  216             if (st.pos > 0) {
  217                 while (st.pos
  218                        && st.s[st.ci[st.pos - 1].offset] ==
  219                        ' ') {
  220                     st.pos--;
  221                     getstr_del_char(&st);
  222                 }
  223                 while (st.pos
  224                        && st.s[st.ci[st.pos - 1].offset] !=
  225                        ' ') {
  226                     st.pos--;
  227                     getstr_del_char(&st);
  228                 }
  229             } else {
  230                 bell();
  231             }
  232             break;
  233         case CTRL('U'): /* delete to beginning of line */
  234             while (st.pos) {
  235                 st.pos--;
  236                 getstr_del_char(&st);
  237             }
  238             break;
  239         case CTRL('K'): /* delete to end-of-line */
  240             st.s[st.ci[st.pos].offset] = 0;
  241             st.len = st.pos;
  242             break;
  243         case CTRL('A'): /* go to beginning of string */
  244             st.pos = 0;
  245             break;
  246         case CTRL('E'): /* go to end of string */
  247             st.pos = st.len;
  248             break;
  249         case KEY_LEFT:  /* move one char backward  */
  250         case CTRL('B'):
  251             if (st.pos > 0)
  252                 st.pos--;
  253             break;
  254         case KEY_RIGHT: /* move one char forward */
  255         case CTRL('F'):
  256             if (st.pos < st.len)
  257                 st.pos++;
  258             break;
  259         case ESCAPE:    /* cancel editing */
  260         case CTRL('G'):
  261             return GETSTRING_ESC;
  262             break;
  263         case ERR:
  264         case KEY_RESIZE:
  265             continue;
  266         default:    /* insert one character */
  267             c[0] = ch;
  268             for (k = 1;
  269                  k < MIN(UTF8_LENGTH(c[0]), UTF8_MAXLEN); k++)
  270                 c[k] = (unsigned char)wgetch(win);
  271             if (st.ci[st.len].offset + k < l) {
  272                 getstr_ins_char(&st, c);
  273                 st.pos++;
  274             }
  275         }
  276     }
  277 
  278     custom_remove_attr(win, ATTR_HIGHEST);
  279 
  280     return st.len == 0 ? GETSTRING_RET : GETSTRING_VALID;
  281 }
  282 
  283 /* Update an already existing string. */
  284 int updatestring(WINDOW * win, char **str, int x, int y)
  285 {
  286     int len = strlen(*str);
  287     char *buf;
  288     enum getstr ret;
  289 
  290     EXIT_IF(len + 1 > BUFSIZ, _("Internal error: line too long"));
  291 
  292     buf = mem_malloc(BUFSIZ);
  293     memcpy(buf, *str, len + 1);
  294 
  295     ret = getstring(win, buf, BUFSIZ, x, y);
  296 
  297     if (ret == GETSTRING_VALID) {
  298         len = strlen(buf);
  299         *str = mem_realloc(*str, len + 1, 1);
  300         EXIT_IF(*str == NULL, _("out of memory"));
  301         memcpy(*str, buf, len + 1);
  302     }
  303 
  304     mem_free(buf);
  305     return ret;
  306 }