<commit_before>/**
 * ui.c -- various curses interfaces
 * Copyright (C) 2009-2013 by <NAME> <<EMAIL>>
 * GoAccess - An Ncurses apache weblog analyzer & interactive viewer
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * A copy of the GNU General Public License is attached to this
 * source distribution for its full text.
 *
 * Visit http://goaccess.prosoftcorp.com for new releases.
 */

/*
 * "_XOPEN_SOURCE" is required for the GNU libc to export "strptime(3)"
 * correctly.
 */
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64

#define _XOPEN_SOURCE 700
#define STDIN_FILENO  0
#define _BSD_SOURCE

#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <pthread.h>
#include <ctype.h>

#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>

#include "ui.h"

#include "commons.h"
#include "error.h"
#include "xmalloc.h"
#include "gmenu.h"
#include "goaccess.h"
#include "parser.h"
#include "settings.h"
#include "util.h"

#ifdef HAVE_LIBGEOIP
GeoIP *geo_location_data;
#endif

/* *INDENT-OFF* */
static const char *sort_choices[][SORT_MAX_OPTS] = {
   {"Hits", "Data", "Bandwidth", NULL},
   {"Hits", "Data", "Bandwidth", "Time Served", "Protocol", "Method", NULL},
   {"Hits", "Data", "Bandwidth", "Time Served", "Protocol", "Method", NULL},
   {"Hits", "Data", "Bandwidth", "Time Served", "Protocol", "Method", NULL},
   {"Hits", "Data", "Bandwidth", "Time Served", NULL},
   {"Hits", "Data", NULL},
   {"Hits", "Data", NULL},
   {"Hits", "Data", NULL},
   {"Hits", "Data", NULL},
   {"Hits", "Data", NULL},
#ifdef HAVE_LIBGEOIP
   {"Hits", "Data", NULL},
#endif
   {"Hits", "Data", NULL},
};
/* *INDENT-ON* */

/* creation - ncurses' window handling */
WINDOW *
create_win (int h, int w, int y, int x)
{
   WINDOW *win = newwin (h, w, y, x);
   if (win == NULL)
      error_handler (__PRETTY_FUNCTION__, __FILE__, __LINE__,
                     "Unable to allocate memory for new WINDOW.");
   return win;
}

/* initialize curses colors */
void
init_colors (void)
{
   use_default_colors ();

   init_pair (COL_BLUE, COLOR_BLUE, -1);
   if (conf.color_scheme == STD_GREEN)
      init_pair (COL_GREEN, COLOR_GREEN, -1);
   else
      init_pair (COL_GREEN, COLOR_WHITE, -1);

   init_pair (COL_RED, COLOR_RED, -1);
   init_pair (COL_BLACK, COLOR_BLACK, -1);
   init_pair (COL_CYAN, COLOR_CYAN, -1);
   init_pair (COL_YELLOW, COLOR_YELLOW, -1);

   if (conf.color_scheme == STD_GREEN)
      init_pair (BLUE_GREEN, COLOR_BLUE, COLOR_GREEN);
   else
      init_pair (BLUE_GREEN, COLOR_BLUE, COLOR_WHITE);

   init_pair (BLACK_GREEN, COLOR_BLACK, COLOR_GREEN);
   init_pair (BLACK_CYAN, COLOR_BLACK, COLOR_CYAN);
   init_pair (WHITE_RED, COLOR_WHITE, COLOR_RED);
}

/* creation - ncurses' window handling */
void
set_input_opts (void)
{
   noecho ();
   halfdelay (10);
   nonl ();
   intrflush (stdscr, FALSE);
   keypad (stdscr, TRUE);
   curs_set (0);

   if (conf.mouse_support)
      mousemask (BUTTON1_CLICKED, NULL);
}

/* delete ncurses window handling */
void
close_win (WINDOW * w)
{
   if (w == NULL)
      return;
   wclear (w);
   wrefresh (w);
   delwin (w);
}

void
generate_time (void)
{
   timestamp = time (NULL);
   now_tm = localtime (&timestamp);
}

/* draw a generic header */
void
draw_header (WINDOW * win, const char *header, int x, int y, int w, int color)
{
   char buf[256];
   snprintf (buf, sizeof buf, "%s%s", " ", header);

   if (conf.color_scheme == STD_GREEN) {
      init_pair (1, COLOR_BLACK, COLOR_GREEN);
      init_pair (2, COLOR_BLACK, COLOR_CYAN);
   } else {
      init_pair (1, COLOR_BLACK, COLOR_WHITE);
      init_pair (2, COLOR_WHITE, -1);
   }
   wattron (win, COLOR_PAIR (color));
   mvwhline (win, y, x, ' ', w);
   mvwaddnstr (win, y, x, buf, w);
   wattroff (win, COLOR_PAIR (color));
}

/* determine the actual size of the main window */
void
term_size (WINDOW * main_win)
{
   getmaxyx (stdscr, term_h, term_w);

   real_size_y = term_h - (MAX_HEIGHT_HEADER + MAX_HEIGHT_FOOTER);
   wresize (main_win, real_size_y, term_w);
   wmove (main_win, real_size_y, 0);
}

static const char *
module_to_label (GModule module)
{
   static const char *modules[] = {
      "Visitors",
      "Requests",
      "Static Requests",
      "Not Found",
      "Hosts",
      "OS",
      "Browsers",
      "Referrers",
      "Referring Sites",
      "Keyphrases",
#ifdef HAVE_LIBGEOIP
      "Geo Location",
#endif
      "Status Codes"
   };

   return modules[module];
}

/* rerender header window to reflect active module */
void
update_active_module (WINDOW * header_win, GModule current)
{
   const char *module = module_to_label (current);
   int col = getmaxx (stdscr);

   char *lbl = xmalloc (snprintf (NULL, 0, "[Active Module: %s]", module) + 1);
   sprintf (lbl, "[Active Module: %s]", module);

   wattron (header_win, COLOR_PAIR (BLUE_GREEN));
   wmove (header_win, 0, 30);
   mvwprintw (header_win, 0, col - strlen (lbl) - 1, "%s", lbl);
   wattroff (header_win, COLOR_PAIR (BLUE_GREEN));
   wrefresh (header_win);

   free (lbl);
}

/* render general statistics */
void
display_general (WINDOW * win, char *ifile, int piping, int processed,
                 int invalid, unsigned long long bandwidth)
{
   char *bw, *size, *log_file;
   char *failed, *not_found, *process, *ref, *req;
   char *static_files, *now, *visitors;

   int x_field = 2, x_value = 0;
   size_t n, i, j, max_field = 0, max_value = 0, mod_val, y;

   typedef struct Field_
   {
      const char *field;
      char *value;              /* char due to log, bw, log_file */
      int color;
   } Field;

   Field fields[] = {
      {T_REQUESTS, NULL, COL_CYAN},
      {T_UNIQUE_VIS, NULL, COL_CYAN},
      {T_REFERRER, NULL, COL_CYAN},
      {T_LOG, NULL, COL_CYAN},
      {T_F_REQUESTS, NULL, COL_CYAN},
      {T_UNIQUE_FIL, NULL, COL_CYAN},
      {T_UNIQUE404, NULL, COL_CYAN},
      {T_BW, NULL, COL_CYAN},
      {T_GEN_TIME, NULL, COL_CYAN},
      {T_STATIC_FIL, NULL, COL_CYAN},
      {"", alloc_string (""), COL_CYAN},
      {T_LOG_PATH, NULL, COL_YELLOW}
   };

   werase (win);
   draw_header (win, T_HEAD, 0, 0, getmaxx (stdscr), 1);

   if (!piping && ifile != NULL) {
      size = filesize_str (file_size (ifile));
      log_file = alloc_string (ifile);
   } else {
      size = alloc_string ("N/A");
      log_file = alloc_string ("STDIN");
   }
   bw = filesize_str ((float) bandwidth);

   /* *INDENT-OFF* */
   failed       = int_to_str (invalid);
   not_found    = int_to_str (g_hash_table_size (ht_not_found_requests));
   process      = int_to_str (processed);
   ref          = int_to_str (g_hash_table_size (ht_referrers));
   req          = int_to_str (g_hash_table_size (ht_requests));
   static_files = int_to_str (g_hash_table_size (ht_requests_static));
   now          = int_to_str (((int) end_proc - start_proc));
   visitors     = int_to_str (g_hash_table_size (ht_unique_visitors));

   fields[0].value = process;
   fields[1].value = visitors;
   fields[2].value = ref;
   fields[3].value = size;
   fields[4].value = failed;
   fields[5].value = req;
   fields[6].value = not_found;
   fields[7].value = bw;
   fields[8].value = now;
   fields[9].value = static_files;
   fields[11].value = log_file;

   n = ARRAY_SIZE (fields);

   /* *INDENT-ON* */
   for (i = 0, y = 2; i < n; i++) {
      mod_val = i % 4;
      if (i > 0 && mod_val == 0) {
         max_field = 0;
         max_value = 0;
         x_field = 2;<commit_msg>Portable way to print time_t is to use long long.<commit_after>/**
 * ui.c -- various curses interfaces
 * Copyright (C) 2009-2013 by <NAME> <<EMAIL>>
 * GoAccess - An Ncurses apache weblog analyzer & interactive viewer
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * A copy of the GNU General Public License is attached to this
 * source distribution for its full text.
 *
 * Visit http://goaccess.prosoftcorp.com for new releases.
 */

/*
 * "_XOPEN_SOURCE" is required for the GNU libc to export "strptime(3)"
 * correctly.
 */
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64

#define _XOPEN_SOURCE 700
#define STDIN_FILENO  0
#define _BSD_SOURCE

#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <pthread.h>
#include <ctype.h>

#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>

#include "ui.h"

#include "commons.h"
#include "error.h"
#include "xmalloc.h"
#include "gmenu.h"
#include "goaccess.h"
#include "parser.h"
#include "settings.h"
#include "util.h"

#ifdef HAVE_LIBGEOIP
GeoIP *geo_location_data;
#endif

/* *INDENT-OFF* */
static const char *sort_choices[][SORT_MAX_OPTS] = {
   {"Hits", "Data", "Bandwidth", NULL},
   {"Hits", "Data", "Bandwidth", "Time Served", "Protocol", "Method", NULL},
   {"Hits", "Data", "Bandwidth", "Time Served", "Protocol", "Method", NULL},
   {"Hits", "Data", "Bandwidth", "Time Served", "Protocol", "Method", NULL},
   {"Hits", "Data", "Bandwidth", "Time Served", NULL},
   {"Hits", "Data", NULL},
   {"Hits", "Data", NULL},
   {"Hits", "Data", NULL},
   {"Hits", "Data", NULL},
   {"Hits", "Data", NULL},
#ifdef HAVE_LIBGEOIP
   {"Hits", "Data", NULL},
#endif
   {"Hits", "Data", NULL},
};
/* *INDENT-ON* */

/* creation - ncurses' window handling */
WINDOW *
create_win (int h, int w, int y, int x)
{
   WINDOW *win = newwin (h, w, y, x);
   if (win == NULL)
      error_handler (__PRETTY_FUNCTION__, __FILE__, __LINE__,
                     "Unable to allocate memory for new WINDOW.");
   return win;
}

/* initialize curses colors */
void
init_colors (void)
{
   use_default_colors ();

   init_pair (COL_BLUE, COLOR_BLUE, -1);
   if (conf.color_scheme == STD_GREEN)
      init_pair (COL_GREEN, COLOR_GREEN, -1);
   else
      init_pair (COL_GREEN, COLOR_WHITE, -1);

   init_pair (COL_RED, COLOR_RED, -1);
   init_pair (COL_BLACK, COLOR_BLACK, -1);
   init_pair (COL_CYAN, COLOR_CYAN, -1);
   init_pair (COL_YELLOW, COLOR_YELLOW, -1);

   if (conf.color_scheme == STD_GREEN)
      init_pair (BLUE_GREEN, COLOR_BLUE, COLOR_GREEN);
   else
      init_pair (BLUE_GREEN, COLOR_BLUE, COLOR_WHITE);

   init_pair (BLACK_GREEN, COLOR_BLACK, COLOR_GREEN);
   init_pair (BLACK_CYAN, COLOR_BLACK, COLOR_CYAN);
   init_pair (WHITE_RED, COLOR_WHITE, COLOR_RED);
}

/* creation - ncurses' window handling */
void
set_input_opts (void)
{
   noecho ();
   halfdelay (10);
   nonl ();
   intrflush (stdscr, FALSE);
   keypad (stdscr, TRUE);
   curs_set (0);

   if (conf.mouse_support)
      mousemask (BUTTON1_CLICKED, NULL);
}

/* delete ncurses window handling */
void
close_win (WINDOW * w)
{
   if (w == NULL)
      return;
   wclear (w);
   wrefresh (w);
   delwin (w);
}

void
generate_time (void)
{
   timestamp = time (NULL);
   now_tm = localtime (&timestamp);
}

/* draw a generic header */
void
draw_header (WINDOW * win, const char *header, int x, int y, int w, int color)
{
   char buf[256];
   snprintf (buf, sizeof buf, "%s%s", " ", header);

   if (conf.color_scheme == STD_GREEN) {
      init_pair (1, COLOR_BLACK, COLOR_GREEN);
      init_pair (2, COLOR_BLACK, COLOR_CYAN);
   } else {
      init_pair (1, COLOR_BLACK, COLOR_WHITE);
      init_pair (2, COLOR_WHITE, -1);
   }
   wattron (win, COLOR_PAIR (color));
   mvwhline (win, y, x, ' ', w);
   mvwaddnstr (win, y, x, buf, w);
   wattroff (win, COLOR_PAIR (color));
}

/* determine the actual size of the main window */
void
term_size (WINDOW * main_win)
{
   getmaxyx (stdscr, term_h, term_w);

   real_size_y = term_h - (MAX_HEIGHT_HEADER + MAX_HEIGHT_FOOTER);
   wresize (main_win, real_size_y, term_w);
   wmove (main_win, real_size_y, 0);
}

static const char *
module_to_label (GModule module)
{
   static const char *modules[] = {
      "Visitors",
      "Requests",
      "Static Requests",
      "Not Found",
      "Hosts",
      "OS",
      "Browsers",
      "Referrers",
      "Referring Sites",
      "Keyphrases",
#ifdef HAVE_LIBGEOIP
      "Geo Location",
#endif
      "Status Codes"
   };

   return modules[module];
}

/* rerender header window to reflect active module */
void
update_active_module (WINDOW * header_win, GModule current)
{
   const char *module = module_to_label (current);
   int col = getmaxx (stdscr);

   char *lbl = xmalloc (snprintf (NULL, 0, "[Active Module: %s]", module) + 1);
   sprintf (lbl, "[Active Module: %s]", module);

   wattron (header_win, COLOR_PAIR (BLUE_GREEN));
   wmove (header_win, 0, 30);
   mvwprintw (header_win, 0, col - strlen (lbl) - 1, "%s", lbl);
   wattroff (header_win, COLOR_PAIR (BLUE_GREEN));
   wrefresh (header_win);

   free (lbl);
}

/* render general statistics */
void
display_general (WINDOW * win, char *ifile, int piping, int processed,
                 int invalid, unsigned long long bandwidth)
{
   char *bw, *size, *log_file;
   char *failed, *not_found, *process, *ref, *req;
   char *static_files, *now, *visitors;

   int x_field = 2, x_value = 0;
   size_t n, i, j, max_field = 0, max_value = 0, mod_val, y;

   typedef struct Field_
   {
      const char *field;
      char *value;              /* char due to log, bw, log_file */
      int color;
   } Field;

   Field fields[] = {
      {T_REQUESTS, NULL, COL_CYAN},
      {T_UNIQUE_VIS, NULL, COL_CYAN},
      {T_REFERRER, NULL, COL_CYAN},
      {T_LOG, NULL, COL_CYAN},
      {T_F_REQUESTS, NULL, COL_CYAN},
      {T_UNIQUE_FIL, NULL, COL_CYAN},
      {T_UNIQUE404, NULL, COL_CYAN},
      {T_BW, NULL, COL_CYAN},
      {T_GEN_TIME, NULL, COL_CYAN},
      {T_STATIC_FIL, NULL, COL_CYAN},
      {"", alloc_string (""), COL_CYAN},
      {T_LOG_PATH, NULL, COL_YELLOW}
   };

   werase (win);
   draw_header (win, T_HEAD, 0, 0, getmaxx (stdscr), 1);

   if (!piping && ifile != NULL) {
      size = filesize_str (file_size (ifile));
      log_file = alloc_string (ifile);
   } else {
      size = alloc_string ("N/A");
      log_file = alloc_string ("STDIN");
   }
   bw = filesize_str ((float) bandwidth);

   /* *INDENT-OFF* */
   failed       = int_to_str (invalid);
   not_found    = int_to_str (g_hash_table_size (ht_not_found_requests));
   process      = int_to_str (processed);
   ref          = int_to_str (g_hash_table_size (ht_referrers));
   req          = int_to_str (g_hash_table_size (ht_requests));
   static_files = int_to_str (g_hash_table_size (ht_requests_static));
   now          = int_to_str (((long long) end_proc - start_proc));
   visitors     = int_to_str (g_hash_table_size (ht_unique_visitors));

   fields[0].value = process;
   fields[1].value = visitors;
   fields[2].value = ref;
   fields[3].value = size;
   fields[4].value = failed;
   fields[5].value = req;
   fields[6].value = not_found;
   fields[7].value = bw;
   fields[8].value = now;
   fields[9].value = static_files;
   fields[11].value = log_file;

   n = ARRAY_SIZE (fields);

   /* *INDENT-ON* */
   for (i = 0, y = 2; i < n; i++) {
      mod_val = i % 4;
      if (i > 0 && mod_val == 0) {
         max_field = 0;
         max_value = 0;
         x_field = 2;
{'fraction_non_alphanumeric': 0.1409273686855994, 'fraction_numerical': 0.009424478512188993, 'mean_word_length': 3.2949271451699946, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5742029', 'n_tokens_mistral': 6060, 'n_tokens_neox': 5886, 'n_words': 1629}