"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.2/src/screen.c" (8 Dec 2017, 13242 Bytes) of package /linux/misc/tin-2.4.2.tar.xz:


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 "screen.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.1_vs_2.4.2.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : screen.c
    4  *  Author    : I. Lea & R. Skrenta
    5  *  Created   : 1991-04-01
    6  *  Updated   : 2017-03-28
    7  *  Notes     :
    8  *
    9  * Copyright (c) 1991-2018 Iain Lea <iain@bricbrac.de>, Rich Skrenta <skrenta@pbm.com>
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. The name of the author may not be used to endorse or promote
   21  *    products derived from this software without specific prior written
   22  *    permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
   25  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
   28  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   30  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35  */
   36 
   37 
   38 #ifndef TIN_H
   39 #   include "tin.h"
   40 #endif /* !TIN_H */
   41 #ifndef TCURSES_H
   42 #   include "tcurses.h"
   43 #endif /* !TCURSES_H */
   44 
   45 int mark_offset = 0;
   46 
   47 #ifndef USE_CURSES
   48     struct t_screen *screen;
   49 #endif /* !USE_CURSES */
   50 
   51 
   52 /*
   53  * Move the cursor to the lower-left of the screen, where it won't be annoying
   54  */
   55 void
   56 stow_cursor(
   57     void)
   58 {
   59     if (!cmd_line)
   60         MoveCursor(cLINES, 0);
   61 }
   62 
   63 
   64 /*
   65  * helper for the varius *_message() functions
   66  * returns a pointer to an allocated buffer with the formatted message
   67  * must be freed if not needed anymore
   68  */
   69 char *
   70 fmt_message(
   71     const char *fmt,
   72     va_list ap)
   73 {
   74     char *msg;
   75 
   76 #ifdef HAVE_VASPRINTF
   77     if (vasprintf(&msg, fmt, ap) == -1) /* something went wrong */
   78 #endif /* HAVE_VASPRINTF */
   79     {
   80         size_t size = LEN;
   81 
   82         msg = my_malloc(size);
   83         /* TODO: realloc msg if necessary */
   84         vsnprintf(msg, size, fmt, ap);
   85     }
   86 
   87     return msg;
   88 }
   89 
   90 
   91 /*
   92  * Centre a formatted colour message at the bottom of the screen
   93  */
   94 void
   95 info_message(
   96     const char *fmt,
   97     ...)
   98 {
   99     char *buf;
  100     va_list ap;
  101 
  102     va_start(ap, fmt);
  103 
  104     clear_message();
  105 #ifdef HAVE_COLOR
  106     fcol(tinrc.col_message);
  107 #endif /* HAVE_COLOR */
  108 
  109     buf = fmt_message(fmt, ap);
  110     center_line(cLINES, FALSE, buf);    /* center the message at screen bottom */
  111     free(buf);
  112 
  113 #ifdef HAVE_COLOR
  114     fcol(tinrc.col_normal);
  115 #endif /* HAVE_COLOR */
  116     stow_cursor();
  117 
  118     va_end(ap);
  119 }
  120 
  121 
  122 /*
  123  * Print a formatted colour message at the bottom of the screen, wait a while
  124  */
  125 void
  126 wait_message(
  127     unsigned int sdelay,
  128     const char *fmt,
  129     ...)
  130 {
  131     char *buf;
  132     va_list ap;
  133 
  134     va_start(ap, fmt);
  135 
  136     clear_message();
  137 #ifdef HAVE_COLOR
  138     fcol(tinrc.col_message);
  139 #endif /* HAVE_COLOR */
  140 
  141     buf = fmt_message(fmt, ap);
  142     my_fputs(buf, stdout);
  143     free(buf);
  144 
  145 #ifdef HAVE_COLOR
  146     fcol(tinrc.col_normal);
  147 #endif /* HAVE_COLOR */
  148     cursoron();
  149     my_flush();
  150 
  151     (void) sleep(sdelay);
  152 /*  clear_message(); would be nice, but tin doesn't expect this yet */
  153     va_end(ap);
  154 }
  155 
  156 
  157 /*
  158  * Print a formatted message to stderr, no colour is added.
  159  * Interesting - this function implicitly clears 'errno'
  160  */
  161 void
  162 error_message(
  163     unsigned int sdelay,
  164     const char *fmt,
  165     ...)
  166 {
  167     char *buf;
  168     va_list ap;
  169 
  170     va_start(ap, fmt);
  171 
  172     errno = 0;
  173     clear_message();
  174 
  175     buf = fmt_message(fmt, ap);
  176     my_fputs(buf, stderr);  /* don't use my_fprintf() here due to %format chars */
  177     my_fflush(stderr);
  178     free(buf);
  179 
  180     if (cmd_line) {
  181         my_fputc('\n', stderr);
  182         fflush(stderr);
  183     } else {
  184         stow_cursor();
  185         (void) sleep(sdelay);
  186         clear_message();
  187     }
  188 
  189     va_end(ap);
  190 }
  191 
  192 
  193 /*
  194  * Print a formatted error message to stderr, no colour is added.
  195  * This function implicitly clears 'errno'
  196  */
  197 void
  198 perror_message(
  199     const char *fmt,
  200     ...)
  201 {
  202     char *buf;
  203     int err;
  204     va_list ap;
  205 
  206     err = errno;
  207     va_start(ap, fmt);
  208 
  209     clear_message();
  210 
  211     if ((buf = fmt_message(fmt, ap)) != NULL) {
  212         error_message(2, "%s: Error: %s", buf, strerror(err));
  213         free(buf);
  214     }
  215 
  216     va_end(ap);
  217 }
  218 
  219 
  220 void
  221 clear_message(
  222     void)
  223 {
  224     if (!cmd_line) {
  225         MoveCursor(cLINES, 0);
  226         CleartoEOLN();
  227         cursoroff();
  228 #ifndef USE_CURSES
  229         my_flush();
  230 #endif /* !USE_CURSES */
  231     }
  232 }
  233 
  234 
  235 void
  236 center_line(
  237     int line,
  238     t_bool inverse,
  239     const char *str)
  240 {
  241     int pos;
  242     int len;
  243 
  244     len = strwidth(str);
  245 
  246     if (!cmd_line) {
  247         if (cCOLS >= len)
  248             pos = (cCOLS - len) / 2;
  249         else
  250             pos = 1;
  251 
  252         MoveCursor(line, pos);
  253         if (inverse) {
  254             StartInverse();
  255             my_flush();
  256         }
  257     }
  258 
  259     if (len >= cCOLS) {
  260         char *buffer;
  261 
  262         buffer = strunc(str, cCOLS - 2);
  263         my_fputs(buffer, stdout);
  264         free(buffer);
  265     } else
  266         my_fputs(str, stdout);
  267 
  268     if (cmd_line)
  269         my_flush();
  270     else {
  271         if (inverse)
  272             EndInverse();
  273     }
  274 }
  275 
  276 
  277 void
  278 draw_arrow_mark(
  279     int line)
  280 {
  281 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  282     wchar_t *wtmp;
  283 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  284 
  285     MoveCursor(line, 0);
  286 
  287     if (tinrc.draw_arrow) {
  288 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  289         if (tinrc.utf8_graphics) {
  290             my_fputwc(CURSOR_HORIZ, stdout);
  291             my_fputwc(CURSOR_ARROW, stdout);
  292         } else
  293 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  294             my_fputs("->", stdout);
  295     } else {
  296 #ifdef USE_CURSES
  297         char buffer[BUFSIZ];
  298         char *s = screen_contents(line, 0, buffer);
  299 #else
  300         char *s = screen[line - INDEX_TOP].col;
  301 #endif /* USE_CURSES */
  302 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  303         if ((wtmp = char2wchar_t(s)) != NULL) {
  304             StartInverse();
  305             my_fputws(wtmp, stdout);
  306             EndInverse();
  307             if (mark_offset && wtmp[mark_offset] == tinrc.art_marked_selected) {
  308                 MoveCursor(line, mark_offset);
  309                 EndInverse();
  310                 my_fputwc((wint_t) wtmp[mark_offset], stdout);
  311             }
  312             free(wtmp);
  313         }
  314 #else
  315         StartInverse();
  316         my_fputs(s, stdout);
  317         EndInverse();
  318         if (mark_offset && s[mark_offset] == tinrc.art_marked_selected) {
  319             MoveCursor(line, mark_offset);
  320             EndInverse();
  321             my_fputc(s[mark_offset], stdout);
  322         }
  323 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  324     }
  325     stow_cursor();
  326 }
  327 
  328 
  329 void
  330 erase_arrow(
  331     void)
  332 {
  333     int line = INDEX_TOP + currmenu->curr - currmenu->first;
  334 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  335     wchar_t *wtmp;
  336 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
  337 
  338     if (!currmenu->max)
  339         return;
  340 
  341     MoveCursor(line, 0);
  342 
  343     if (tinrc.draw_arrow)
  344         my_fputs("  ", stdout);
  345     else {
  346 #ifdef USE_CURSES
  347         char buffer[BUFSIZ];
  348         char *s = screen_contents(line, 0, buffer);
  349 #else
  350         char *s;
  351 
  352         if (line - INDEX_TOP < 0) /* avoid underruns */
  353             line = INDEX_TOP;
  354 
  355         s = screen[line - INDEX_TOP].col;
  356 #endif /* USE_CURSES */
  357         EndInverse();
  358 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
  359         if ((wtmp = char2wchar_t(s)) != NULL) {
  360             my_fputws(wtmp, stdout);
  361             if (mark_offset && wtmp[mark_offset] == tinrc.art_marked_selected) {
  362                 MoveCursor(line, mark_offset);
  363                 StartInverse();
  364                 my_fputwc((wint_t) wtmp[mark_offset], stdout);
  365                 EndInverse();
  366             }
  367             free(wtmp);
  368         }
  369 #else
  370         my_fputs(s, stdout);
  371         if (mark_offset && s[mark_offset] == tinrc.art_marked_selected) {
  372             MoveCursor(line, mark_offset);
  373             StartInverse();
  374             my_fputc(s[mark_offset], stdout);
  375             EndInverse();
  376         }
  377 #endif /* MULTIBYTE_ABLE && !NOLOCALE */
  378     }
  379 }
  380 
  381 
  382 void
  383 show_title(
  384     const char *title)
  385 {
  386     int col;
  387 
  388     col = cCOLS - strwidth(_(txt_type_h_for_help));
  389     if (col > 0) {
  390         MoveCursor(0, col);
  391 #ifdef HAVE_COLOR
  392         fcol(tinrc.col_title);
  393 #endif /* HAVE_COLOR */
  394         /* you have mail message in */
  395         my_fputs((mail_check() ? _(txt_you_have_mail) : _(txt_type_h_for_help)), stdout);
  396 
  397 #ifdef HAVE_COLOR
  398         fcol(tinrc.col_normal);
  399 #endif /* HAVE_COLOR */
  400     }
  401     center_line(0, TRUE, title); /* wastes some space on the left */
  402 }
  403 
  404 
  405 void
  406 ring_bell(
  407     void)
  408 {
  409 #ifdef USE_CURSES
  410     if (!cmd_line)
  411         beep();
  412     else {
  413 #endif /* USE_CURSES */
  414     my_fputc('\007', stdout);
  415     my_flush();
  416 #ifdef USE_CURSES
  417     }
  418 #endif /* USE_CURSES */
  419 }
  420 
  421 
  422 void
  423 spin_cursor(
  424     void)
  425 {
  426     static const char buf[] = "|/-\\|/-\\ "; /* don't remove the tailing space! */
  427     static unsigned short int i = 0;
  428 
  429     if (batch_mode)
  430         return;
  431 
  432     if (i > 7)
  433         i = 0;
  434 
  435 #ifdef HAVE_COLOR
  436     fcol(tinrc.col_message);
  437 #endif /* HAVE_COLOR */
  438     my_printf("\b%c", buf[i++]);
  439     my_flush();
  440 #ifdef HAVE_COLOR
  441     fcol(tinrc.col_normal);
  442 #endif /* HAVE_COLOR */
  443 }
  444 
  445 
  446 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY)
  447 #   define DISPLAY_FMT "%s %3d%% "
  448 #else
  449 #   define DISPLAY_FMT "%s %3d%%"
  450 #endif /* HAVE_CLOCK_GETTIME || HAVE_GETTIMEOFDAY */
  451 /*
  452  * progressmeter in %
  453  */
  454 void
  455 show_progress(
  456     const char *txt,
  457     t_artnum count,
  458     t_artnum total)
  459 {
  460     char display[LEN];
  461     int ratio;
  462     time_t curr_time;
  463     static char last_display[LEN];
  464     static int last_ratio;
  465     static t_artnum last_total;
  466     static time_t last_update;
  467 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY)
  468     static t_artnum last_count;
  469     static int average;
  470     static int samples;
  471     static int last_secs_left;
  472     static int sum;
  473     char *display_format;
  474     int time_diff;
  475     int secs_left;
  476     t_artnum count_diff;
  477     static struct t_tintime last_time;
  478     static struct t_tintime this_time;
  479 #endif /* HAVE_CLOCK_GETTIME || HAVE_GETTIMEOFDAY */
  480 
  481     if (batch_mode || count <= 0 || total <= 1)
  482         return;
  483 
  484     /* If this is a new progress meter, start recalculating */
  485     if ((last_total != total) || (count == 1)) {
  486         last_ratio = -1;
  487         last_display[0] = '\0';
  488         last_update = time(NULL) - 2;
  489     }
  490 
  491     curr_time = time(NULL);
  492     ratio = (int) ((count * 100) / total);
  493     if ((ratio == last_ratio) && (curr_time - last_update < 2))
  494         /*
  495          * return if ratio did not change and less than
  496          * 2 seconds since last update to reduce output
  497          */
  498         return;
  499 
  500     last_update = curr_time;
  501 
  502 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY)
  503     display_format = my_malloc(strlen(DISPLAY_FMT) + strlen(_(txt_remaining)) + 1);
  504     strcpy(display_format, DISPLAY_FMT);
  505 
  506     if (last_ratio == -1) {
  507         /* Don't print the time remaining */
  508         snprintf(display, sizeof(display), display_format, txt, ratio);
  509 
  510         /* Reset the variables */
  511         sum = average = samples = last_secs_left = 0;
  512     } else {
  513         /* Get the current time */
  514         tin_gettime(&this_time);
  515         time_diff = (this_time.tv_sec - last_time.tv_sec) * 1000000;
  516         time_diff += ((this_time.tv_nsec - last_time.tv_nsec) / 1000);
  517         count_diff = (count - last_count);
  518 
  519         if (!count_diff) /* avoid div by zero */
  520             count_diff++;
  521 
  522         /*
  523          * Calculate a running average based on the last 20 samples. For the
  524          * first 19 samples just add all and divide by the number of samples.
  525          * From the 20th sample on use only the last 20 samples to calculate
  526          * the running averave. To make things easier we don't want to store
  527          * and keep track of all of them, so we assume that the first sample
  528          * was close to the current average and subtract it from sum. Then,
  529          * the new sample is added to the sum and the sum is divided by 20 to
  530          * get the new average.
  531          */
  532         if (samples == 20) {
  533             sum -= average;
  534             sum += (time_diff / count_diff);
  535             average = sum / 20;
  536         } else {
  537             sum += (time_diff / count_diff);
  538             average = sum / ++samples;
  539         }
  540 
  541         if (average >= 1000000)
  542             secs_left = (total - count) * (average / 1000000);
  543         else
  544             secs_left = ((total - count) * average) / 1000000;
  545 
  546         if (secs_left < 0)
  547             secs_left = 0;
  548 
  549         if ((secs_left > 0) && (last_secs_left == 0))
  550             last_secs_left = secs_left;
  551 
  552         if (samples < 5)
  553             /* Don't print the time remaining */
  554             snprintf(display, sizeof(display), display_format, txt, ratio);
  555         else {
  556             /* Don't allow time remaining to increase by 1 or 2 seconds */
  557             if ((secs_left == last_secs_left + 1) || (secs_left == last_secs_left + 2))
  558                 secs_left = last_secs_left;
  559             else if (secs_left < last_secs_left)
  560                 last_secs_left = secs_left;
  561             strcat(display_format, _(txt_remaining));
  562             snprintf(display, sizeof(display), display_format, txt, ratio, secs_left / 60, secs_left % 60);
  563         }
  564     }
  565     free(display_format);
  566 
  567     last_count = count;
  568     tin_gettime(&last_time);
  569 #else
  570     snprintf(display, sizeof(display), DISPLAY_FMT, txt, ratio);
  571 #endif /* HAVE_CLOCK_GETTIME || HAVE_GETTIMEOFDAY */
  572 
  573     /* Only display text if it changed from last time */
  574     if (strcmp(display, last_display)) {
  575         char *tmp;
  576 
  577         if (RawState()) {
  578             clear_message();
  579             MoveCursor(cLINES, 0);
  580         } else {
  581             my_printf("\r");
  582             my_flush();
  583             CleartoEOLN();
  584         }
  585 
  586 #ifdef HAVE_COLOR
  587         if (RawState())
  588             fcol(tinrc.col_message);
  589 #endif /* HAVE_COLOR */
  590 
  591         /*
  592          * TODO: depending on the length of the newsgroup name
  593          * it's possible to cut away a great part of the progress meter
  594          * perhaps we should shorten the newsgroup name instead?
  595          */
  596         my_printf("%s", sized_message(&tmp, "%s", display));
  597         free(tmp);
  598 
  599 #ifdef HAVE_COLOR
  600         if (RawState())
  601             fcol(tinrc.col_normal);
  602 #endif /* HAVE_COLOR */
  603 
  604 #ifndef USE_CURSES
  605         if (!RawState())
  606             MoveCursor(cLINES, 0);
  607 #endif /* !USE_CURSES */
  608 
  609         my_flush();
  610         STRCPY(last_display, display);
  611     }
  612 
  613     last_total = total;
  614     last_ratio = ratio;
  615 }