/*
 * slmon
 *
 * Copyright (C) 2000, 2001, 2002 Krzysztof Luks <m00se@iq.pl>
 *
 * Some parts of this file are based on WMMon.app and GTop.
 *
 * WMMon.app is copyright (c) 1997, 1998 by Martijn Pieterse and
 * Antoine Nulle.
 *
 * GTop is copyright (c) 1997,98 Radek Doulík.
 *
 * This program is distributed under the GPL license. For details see
 * COPYING text.
 *
 * Author: Krzysztof Luks <m00se@iq.pl>
 * Some changes contributed by Ryan Wood
 *
 * $Date: 2004/06/20 15:56:48 $
 * $Revision: 1.8 $
 *
 */

#include "draw.h"

#include <glibtop/netload.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*
 * Clear screen using color n. This should be used instead of SLsmg_cls() to
 * avoid strange transparency problems in gnome-terminal.
 */

void slmon_clear_screen(int col)
{
	SLsmg_set_color(col);
	SLsmg_fill_region(0, 0, SLtt_Screen_Rows, SLtt_Screen_Cols, ' ');
}

/*
 * S-Lang initialistaion
 */

void init_slang(void)
{
    SLtt_get_terminfo();	/* S-Lang initialization */
    SLang_init_tty(-1, 0, 0);
    SLsmg_init_smg();
    SLtt_set_cursor_visibility(0);

    SLtt_set_color(5, NULL, col_stat, col_stba);	/* status line */
    SLtt_set_color(6, NULL, col_norm, col_back);	/* description */
    SLtt_set_color(7, NULL, col_valu, col_back);	/* value */

    /* Gauge gradient values  */
    SLtt_set_color(10, NULL, col_gra1, col_back);	/* 00 - 09 */
    SLtt_set_color(11, NULL, col_gra2, col_back);	/* 10 - 19 */
    SLtt_set_color(12, NULL, col_gra3, col_back);	/* 20 - 30 */

    /* Too much inverse video look terribly ugly on monochrome terminals */
    if (do_bold)
	SLtt_set_mono(6, NULL, SLTT_BOLD_MASK);
    else
	SLtt_set_mono(6, NULL, 0);
    SLtt_set_mono(7, NULL, 0);
    SLtt_set_mono(10, NULL, 0);
    SLtt_set_mono(11, NULL, 0);
    SLtt_set_mono(12, NULL, 0);

    if (height > SLtt_Screen_Rows)
	height = SLtt_Screen_Rows;
    else if (height < 20)
	height = 20;
}

/*
 * Draw gauge begining at (row, col).
 */

void draw_gauge(int row, int col, int value, char *caption, int align)
{
    int i;
    int color = 10;

    SLsmg_gotorc(row, col);
    SLsmg_erase_eol();

    if (align == GAUGE_RIGHT) {
	SLsmg_set_color(6);
	SLsmg_printf("%s ", caption);
    } else if (align == GAUGE_LEFT) {
	SLsmg_set_color(7);
	SLsmg_printf("%3d%% ", value);
    }
    SLsmg_set_color(7);
    SLsmg_printf("[");

    if (align == GAUGE_LEFT) {
	SLsmg_gotorc(row, col + conf.gauge_len + 6);	/* 6 == strlen("xxx% ["); */
	SLsmg_set_color(7);
	SLsmg_printf("]");
	SLsmg_set_color(6);
	SLsmg_printf(" %s", caption);
	SLsmg_gotorc(row, col + 6);	/* 6 == strlen("xxx% ["); */
    } else if (align == GAUGE_RIGHT) {
	SLsmg_gotorc(row, col + conf.gauge_len + strlen(caption) + 1);
	SLsmg_set_color(7);
	SLsmg_printf("]");
	SLsmg_printf("%3d%% ", value);
	SLsmg_gotorc(row, col + strlen(caption) + 2);
    }

    value *= conf.gauge_len;
    value /= 100;
    if (value > 100)		/* Just in case someone tries to cheat us ;->> */
	value = 100;

    for (i = 0; i < value; i++) {
	color = i / (conf.gauge_len / 3) + 10;	/* Gauge colors: 10, 11, 12 */
	if (color > 12)		/* Let's try to be smart ;)) */
	    color = 12;
	SLsmg_set_color(color);
	SLsmg_printf("*");
    }
}

/*
 * Draw top and bottom status lines
 */

void draw_status(void)
{
    time_t curtime;		/* Current time */
    struct tm *loctime;		/* Local time */
    char time_str[64];
    struct utsname hi;		/* host info */
    int up_d, up_h, up_m, up_s;	/* Uptime */

    uname(&hi);			/* get host information */
    get_uptime(&up_d, &up_h, &up_m, &up_s);

    curtime = time(NULL);
    loctime = localtime(&curtime);
    strftime(time_str, 64, "%a, %d %B %Y, %H:%M:%S", loctime);

    /* Upper status line */

    SLsmg_gotorc(0, 0);
    SLsmg_set_color(5);
    SLsmg_erase_eol();
    SLsmg_printf("%s %s", PACKAGE, VERSION);
    if (mode == MODE_H)
	SLsmg_printf("\trspace: %d cspace: %d", rspace, cspace);
    else if (mode == MODE_M)
	SLsmg_printf("\tgauge length: %d ", conf.gauge_len);
    SLsmg_gotorc(0, SLtt_Screen_Cols - strlen(time_str));
    SLsmg_printf("%s", time_str);	/* date/time */

    /* Lower status line */

    SLsmg_gotorc(height - 2, 0);
    SLsmg_printf("%s %s %s %s, %d users", hi.nodename, hi.sysname,
		 hi.release, hi.machine, users());
    SLsmg_erase_eol();
    if (up_d > 0) {
	SLsmg_gotorc(height - 2, SLtt_Screen_Cols - 21);
	SLsmg_printf("Uptime: %3dd %02d:%02d:%02d", up_d, up_h, up_m,
		     up_s);
    } else {
	SLsmg_gotorc(height - 2, SLtt_Screen_Cols - 16);
	SLsmg_printf("Uptime: %02d:%02d:%02d", up_h, up_m, up_s);
    }
}

/*
 * Draw histogram frame and caption
 */

void draw_histogram(char *caption)
{
    int r = height;
    int c = SLtt_Screen_Cols;
    int r2 = rspace * 2;
    int c2 = cspace * 2;

    /* Box */
    SLsmg_set_color(7);
    SLsmg_draw_box(rspace, cspace, r - r2, c - c2);

    /* If there is enouch space for the scale, than draw it */
    if (cspace >= 4) {
	SLsmg_gotorc(rspace, cspace - 4);
	SLsmg_printf("100%%");
	SLsmg_gotorc(r / 2, cspace - 4);
	SLsmg_printf(" 50%%");
	SLsmg_gotorc(r - rspace - 1, cspace - 4);
	SLsmg_printf("  0%%");
    }

    /* Caption */
    if (caption != NULL) {
	SLsmg_gotorc(rspace, (c / 2) - (strlen(caption) / 2) - 2);
	SLsmg_printf("[ ");
	SLsmg_set_color(6);
	SLsmg_printf("%s", caption);
	SLsmg_set_color(7);
	SLsmg_printf(" ]");
    }
}

/*
 * Draw value inside histogram frame.
 */

void draw_histogram_value(int value, int pos)
{
    value *= height - rspace * 2 - 3;
    value /= 100;
    SLsmg_set_color(7);
    SLsmg_gotorc(height - value - rspace - 2, cspace + pos + 1);
    SLsmg_draw_vline(value + 1);
}

/*
 * Clear histogram except frame
 */

void clear_histogram(void)
{
    int r2 = rspace * 2;
    int c2 = cspace * 2;

    SLsmg_set_color(7);

    /* We have to be careful not to erase frame */
    SLsmg_fill_region(rspace + 1, cspace + 1, height - r2 - 2,
		      SLtt_Screen_Cols - c2 - 2, ' ');
}

/*
 * Print memory usage
 */

void print_mem(int r, int c)
{
    u_int64_t m_free, m_total, m_used;
    u_int64_t s_total, s_free, s_used;
    glibtop_mem m;
    glibtop_swap s;

    glibtop_get_mem(&m);
    glibtop_get_swap(&s);

    m_free = m.free;
    m_total = m.total;
    m_used = m.used;
    s_free = s.free;
    s_total = s.total;
    s_used = s.used;

    SLsmg_set_color(6);
    SLsmg_gotorc(r++, c);
    SLsmg_printf("\tMemory:\t\t\tSwap:");
    SLsmg_gotorc(r++, c);
    SLsmg_erase_eol();
    SLsmg_printf("Total:\t");
    SLsmg_set_color(7);
    SLsmg_printf("%12Ld \t\t%12Ld [%c]", m_total / unit_div[conf.mem],
		 s_total / unit_div[conf.mem], unit_name[conf.mem]);
    SLsmg_gotorc(r++, c);
    SLsmg_set_color(6);
    SLsmg_erase_eol();
    SLsmg_printf("Used:\t");
    SLsmg_set_color(7);
    SLsmg_printf("%12Ld \t\t%12Ld [%c]", m_used / unit_div[conf.mem],
		 s_used / unit_div[conf.mem], unit_name[conf.mem]);
    SLsmg_gotorc(r++, c);
    SLsmg_set_color(6);
    SLsmg_erase_eol();
    SLsmg_printf("Free:\t");
    SLsmg_set_color(7);
    SLsmg_printf("%12Ld \t\t%12Ld [%c]", m_free / unit_div[conf.mem],
		 s_free / unit_div[conf.mem], unit_name[conf.mem]);
}

/*
 * Print keybindings
 */

void print_keys(int mode)
{
    SLsmg_set_color(6);
    SLsmg_gotorc(height - 1, 0);
    SLsmg_erase_eol();

    SLsmg_write_string("q: quit  ?: help  ");

    switch (mode) {
    case MODE_M:
	SLsmg_write_string("u: mem unit  U: fs unit  up,down: fs scroll");
	break;
    case MODE_H:
	SLsmg_write_string("h: histogram mode");
	break;
    case MODE_N:
	SLsmg_write_string("u: net unit n: new interface d: delete interface");
	break;
    case MODE_P:
	SLsmg_write_string("PgUp,PgDown,up,down: scroll, k:SIGTERM, K:spec signal");
	break;
    case MODE_X:
	SLsmg_write_string("SPC,ENTER:  leave help");
	break;
    }
}

/*
 * Print machine's load average
 */

void print_ldavg(int r, int c)
{
    glibtop_loadavg l;
    glibtop_get_loadavg(&l);
}

/*
 * Print filesystem information in df(1) like style
 */
void print_fs(int r, int c)
{
    int i, gauge_tmp, j = 1;
    int fs_count = 0, use;
    double fs_size, fs_used, fs_avail;
    double tmp1, tmp2;
    char unit;
    glibtop_mountlist ml;
    glibtop_mountentry *me, *me_valid;
    glibtop_fsusage f;

    me = glibtop_get_mountlist(&ml, 0);

    /* Alloc memory for all fileststems... */
    me_valid =
	(glibtop_mountentry *) malloc(ml.number *
				      sizeof(glibtop_mountentry));
    /* ...but choose only those that have non-zero size... */
    for (i = 0; i < ml.number; i++) {
	glibtop_get_fsusage(&f, me[i].mountdir);
	if (f.blocks)
	    me_valid[fs_count++] = me[i];
    }

    /* ...and free unused part. Dunno if there's a better way. */
    me_valid = realloc(me_valid, fs_count * sizeof(glibtop_mountentry));

    /* Check whether we didn't go beyond valid boundary */
    if (conf.fs_first + conf.fs_max >= fs_count)
	conf.fs_first =
	    conf.fs_max > fs_count ? 0 : fs_count - conf.fs_max;

    /* back up gauge length */
    gauge_tmp = conf.gauge_len;
    conf.gauge_len = 12;

    SLsmg_gotorc(r, c);
    SLsmg_set_color(6);

    /* print header */
    SLsmg_printf("%-19s %-13s %-10s %-9s %-9s %-9s", "Percent Used",
		 "Mount point", "Type", "Size", "Used", "Avail");

    for (i = conf.fs_first;
	 i < fs_count && i < conf.fs_max + conf.fs_first; i++) {
	glibtop_get_fsusage(&f, me_valid[i].mountdir);
	unit = unit_name[conf.fs + 1];
	fs_size = (double) f.blocks;
	fs_used = (double) (f.blocks - f.bfree);
	fs_avail = (double) f.bavail;
	use = (int) (fs_size - fs_avail) / fs_size * 100.0;
	fs_size = (double) fs_size / 2.0 / unit_div[conf.fs];
	fs_used = (double) fs_used / 2.0 / unit_div[conf.fs];
	fs_avail = (double) fs_avail / 2.0 / unit_div[conf.fs];

	SLsmg_gotorc(r + j, c);
	draw_gauge(r + j, c, use, me_valid[i].mountdir, GAUGE_LEFT);
	SLsmg_set_color(7);
	SLsmg_gotorc(r + j, c + 34);
	if (conf.fs > 1)
	    SLsmg_printf("%-8s %9.2f %9.2f %9.2f [%c]", me_valid[i].type,
			 fs_size, fs_used, fs_avail, unit);
	else
	    SLsmg_printf("%-8s %9.0f %9.0f %9.0f [%c]", me_valid[i].type,
			 fs_size, fs_used, fs_avail, unit);
	j++;
    }
    g_free(me);
    g_free(me_valid);
    conf.gauge_len = gauge_tmp;

    /* if we haven't displayed all entries we need to draw a scrollbar */
    if (conf.fs_max < fs_count) {
	tmp1 = (double) conf.fs_first + conf.fs_max;
	tmp2 = tmp1 / (double) fs_count;
	tmp2 *= 100.0;
	draw_scrollbar(r + 1, c + 77, conf.fs_max + 0, (int) tmp2);
    }
}

int print_iface(int r, int c, char *name, unsigned long last_in, unsigned long last_out)
{
    glibtop_netload nload;
    unsigned long mtu, s, a, p_in, p_out, e_in, e_out, coll;
    char add[20] = { 0 }, sub[20] = { 0 }, un;
    double b_in, b_out, speed_in, speed_out, scale;
    char un_in, un_out;
    char flags[80] = { 0 };

    glibtop_get_netload(&nload, name);

    if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_UP))
	strcat(flags, "flags: UP ");
    else
	strcat(flags, "flags: DOWN ");
    if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_DEBUG))
	strcat(flags, "DEBUG ");
    if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_LOOPBACK))
	strcat(flags, "LOOPBACK ");
    if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_POINTOPOINT))
	strcat(flags, "POINTOPOINT ");
   if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_RUNNING))
	strcat(flags, "RUNNING ");
    if(nload.if_flags & (1 << GLIBTOP_IF_FLAGS_PROMISC))
	strcat(flags, "PROMISC");

    mtu = (unsigned long) nload.mtu;	//
    s = (unsigned long) nload.subnet;	//
    a = (unsigned long) nload.address;	//
    p_in = (unsigned long) nload.packets_in;	//
    p_out = (unsigned long) nload.packets_out;	//
    b_in = (double) nload.bytes_in / unit_div[conf.net];	//
    b_out = (double) nload.bytes_out / unit_div[conf.net];	//
    e_in = (unsigned long) nload.errors_in;
    e_out = (unsigned long) nload.errors_out;
    coll = (unsigned long) nload.collisions;
    speed_in = (double) (nload.bytes_in - last_in);
    speed_out = (double) (nload.bytes_out - last_out);
    scale = (double) 1000000 / (update_time + 10000);
    speed_in *= scale;
    speed_out *= scale;

    if ( speed_in >= 524288 ) {
	speed_in /= 1048576;
	un_in = 'M';
    } else {
	speed_in /= 1024;
	un_in = 'k';
    }
    if ( speed_out >= 524288 ) {
	speed_out /= 1048576;
	un_out = 'M';
    } else {
	speed_out /= 1024;
	un_out = 'k';
    }

    slmon_update_net_throughput(name, nload.bytes_in, nload.bytes_out);

    un = unit_name[conf.net];

    inet_ntop(AF_INET, &s, sub, 19);
    inet_ntop(AF_INET, &a, add, 19);

    SLsmg_gotorc(r, c);
    SLsmg_set_color(7);

    SLsmg_printf("%s", name);
    SLsmg_gotorc(r, c  + 8);
    SLsmg_printf("%s", add);
    SLsmg_gotorc(r, c  + 26);
    SLsmg_printf("%d", coll);
    SLsmg_gotorc(r, c  + 37);
    
    if (conf.net == 0){
	SLsmg_printf("%.lf%c", b_out, un);
	SLsmg_gotorc(r, c  + 47);
	if (un_out == 'M')
	    SLsmg_set_color(15);
	SLsmg_printf("%.2lf%c/s", speed_out, un_out);
	SLsmg_set_color(7);
	SLsmg_gotorc(r, c  + 58);
	SLsmg_printf("%.lf%c", b_in, un);
	SLsmg_gotorc(r, c  + 68);
	if (un_in == 'M')
	    SLsmg_set_color(15);
	SLsmg_printf("%.2lf%c/s", speed_in, un_in);
	SLsmg_set_color(7);
     } else {
	SLsmg_printf("%.1lf%c", b_out, un);
	SLsmg_gotorc(r, c  + 47);
	if (un_out == 'M')
	    SLsmg_set_color(15);
	SLsmg_printf("%.2lf%c/s", speed_out, un_out);
	SLsmg_set_color(7);
	SLsmg_gotorc(r, c  + 58);
	SLsmg_printf("%.1lf%c", b_in, un);
	SLsmg_gotorc(r, c  + 68);
	if (un_in == 'M')
	    SLsmg_set_color(15);
	SLsmg_printf("%.2lf%c/s", speed_in, un_in);
	SLsmg_set_color(7);
     }
    
    return 1; //height of status
}

/*
 * Draw histogram mode
 */

void draw_mode_h(void)
{
    char *capt;

    capt = cpu_caption(cur_cpu);
    draw_histogram_value(cpu_calc(cur_cpu), pos);
    if (redraw == 1) {
	draw_histogram(capt);
	redraw = 0;
    }
    if (++pos >= SLtt_Screen_Cols - (2 * cspace) - 1) {
	clear_histogram();
	pos = 0;
    }
    free(capt);
}

/*
 * Draw gauge mode
 */

void draw_mode_g(void)
{
    int j;
    char *capt;

    SLsmg_gotorc(2, 0);
    SLsmg_set_color(7);
    SLsmg_forward(5);		/* 5 == "xxx% " */
    SLsmg_printf("0%%");
    SLsmg_forward(conf.gauge_len - 4);	/* 4 == "100%%" */
    SLsmg_printf("100%%");
    SLsmg_set_color(6);
    SLsmg_printf(" Scale");

    for (j = 0; j <= conf.cpus; j++) {
	capt = cpu_caption(j);
	draw_gauge(3 + j, 0, cpu_calc(j), capt, GAUGE_LEFT);
	free(capt);
    }

    if (!(fnord % 2)) {		/* Update these stats every other cycle */
	print_mem(5 + j, 0);
	print_ldavg(10 + j, 0);
	print_fs(12 + j, 0);
    }

}

/*
 * Draw network mode
 */

void draw_mode_n(void)
{
    struct slmon_net *net;
    int num = 0, first;

    if (conf.iface == NULL || conf.iface_count == 0) {
	SLsmg_gotorc(5, (SLtt_Screen_Cols / 2) - 12);
	SLsmg_set_color(7);
	SLsmg_write_string("No interfaces specified.");
	return;
    }

    net = conf.iface;
    first = conf.iface_first;

    /* clear the screen to avoid artefacts when scrolling */
    SLsmg_set_color(7);
    SLsmg_fill_region(1, 0, SLtt_Screen_Rows - 3, SLtt_Screen_Cols, ' ');

    /* skip ifaces we don't want to see */
    while(first > 0 && net != NULL) {
	first--;
	net = net->next;
    }

    /* print the remaining ones */
    while(net != NULL) {
	if(num + 3 > SLtt_Screen_Rows - 2)
	    break; /* no more space left on screen */
	num += print_iface(2 + num, 1, net->name, net->last_in, net->last_out);
	net = net->next;
    }

    /* draw scrollbar */
    SLsmg_gotorc(1, 1);
    SLsmg_set_color(6);
    SLsmg_printf("INT     IP                Collisions Sent:     k/s        Recieved: k/s");
    SLsmg_set_color(7);
    draw_scrollbar(2, 0, SLtt_Screen_Rows - 4, (conf.iface_first * 100) / conf.iface_count);
}

/*
 * Draw processes mode
 * ps -e -o user,pid,pcpu,pmem,vsz,rsz,stat,cmd
 */

void draw_mode_p(void)
{
    slmon_proc p;
    int i, num;
    double prct;

    plist = slmon_get_proclist(&num);

    if (plist) {
	qsort(plist, num, sizeof(slmon_proc), conf.sort_func);

	if (conf.proc_first + SLtt_Screen_Rows - 5 > num)
	    conf.proc_first = num - SLtt_Screen_Rows + 5;

	if (conf.proc_curr >= num)
	    conf.proc_curr = num - 1;

	if (conf.proc_first < 0)
	    conf.proc_first = 0;

	if (conf.proc_curr < 0)
	    conf.proc_curr = 0;

	SLsmg_set_color(6);
	SLsmg_fill_region(1, 0, SLtt_Screen_Rows - 3, SLtt_Screen_Cols, ' ');
	SLsmg_gotorc(1, 1);
	SLsmg_printf("USER       PID %%CPU %%MEM   VSZ  RSS STAT COMMAND");
	if (SLtt_Screen_Rows - 5 < num) {
	    prct = (double) conf.proc_first + SLtt_Screen_Rows - 5;
	    prct /= (double) num;
	    prct *= 100.0;
	    draw_scrollbar(2, 0, SLtt_Screen_Rows - 5, (int) prct);
	}

	for (i = 0; i < num && i < SLtt_Screen_Rows - 5; i++) {
	    p = plist[i + conf.proc_first];
	    if(i + conf.proc_first == conf.proc_curr)
		SLsmg_set_color(5);
	    else
		SLsmg_set_color(7);
	    SLsmg_gotorc(2 + i, 1);
	    SLsmg_printf("%-8s %5d %2u.%1u %2u.%1u %5d %4d %-4c %s", p.user, p.pid, p.pcpu / 10, p.pcpu % 10, p.pmem / 10, p.pmem % 10, p.vsz, p.rss, p.state, p.args);
	    SLsmg_erase_eol();
	}
	free(plist);
    }
}

void draw_mode_x(void)
{
    SLsmg_set_color(7);
    SLsmg_gotorc(1, (SLtt_Screen_Cols / 2) - 2);
    SLsmg_printf("Help");
    SLsmg_set_color(6);
    SLsmg_gotorc(3, 1);
    SLsmg_printf("Mode changing:");
    SLsmg_set_color(7);
    SLsmg_write_wrapped_string(HELP_MODE, 4, 1, SLtt_Screen_Rows - 2,
			       SLtt_Screen_Cols - 1, 0);
    SLsmg_gotorc(10, 1);
    SLsmg_set_color(6);
    SLsmg_printf("Exiting:");
    SLsmg_set_color(7);
    SLsmg_write_wrapped_string(HELP_QUIT, 11, 1, SLtt_Screen_Rows - 2,
			       SLtt_Screen_Cols - 1, 0);
    SLsmg_gotorc(13, 1);
    SLsmg_set_color(6);
    SLsmg_printf("Histogram mode:");
    SLsmg_set_color(7);
    SLsmg_write_wrapped_string(HELP_HIST, 14, 1, SLtt_Screen_Rows - 2,
			       SLtt_Screen_Cols - 1, 0);
    SLsmg_gotorc(3, 36);
    SLsmg_set_color(6);
    SLsmg_printf("Proc mode:");
    SLsmg_set_color(7);
    SLsmg_write_wrapped_string(HELP_PROC, 4, 36, SLtt_Screen_Rows - 2,
			       SLtt_Screen_Cols - 1, 0);
    SLsmg_gotorc(9, 36);
    SLsmg_set_color(6);
    SLsmg_printf("Net mode:");
    SLsmg_set_color(7);
    SLsmg_write_wrapped_string(HELP_NET, 10, 36, SLtt_Screen_Rows - 2,
			       SLtt_Screen_Cols - 1, 0);
    SLsmg_gotorc(12, 36);
    SLsmg_set_color(6);
    SLsmg_printf("Main mode:");
    SLsmg_set_color(7);
    SLsmg_write_wrapped_string(HELP_MAIN, 13, 36, SLtt_Screen_Rows - 2,
			       SLtt_Screen_Cols - 1, 0);

}

/*
 * Draw scrollbar
 */

void draw_scrollbar(int r, int c, int h, int prct)
{
    int skip = (prct * h) / 100 - 1;

    if (skip >= h)
	skip = h - 1;

    SLsmg_set_color(7);
    SLsmg_gotorc(r, c);
    SLsmg_draw_vline(h);
    SLsmg_gotorc(r + skip, c);
    SLsmg_printf("*");
}

void slmon_status_msg(char *format, ...)
{
    va_list ptr;

    SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
    SLsmg_erase_eol();

    va_start(ptr, format);
    SLsmg_vprintf(format, ptr);
    va_end(ptr);
    SLsmg_refresh();
}





syntax highlighted by Code2HTML, v. 0.9.1