/* Hello, Emacs, this is -*-C-*-
* $Id: linux.trm,v 1.30 2011/01/11 01:04:13 sfeam Exp $
*
*/
/* GNUPLOT - linux.trm */
/*[
* Copyright 1993, 1998, 2004
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the complete modified source code. Modifications are to
* be distributed as patches to the released version. Permission to
* distribute binaries produced by compiling modified sources is granted,
* provided you
* 1. distribute the corresponding source modifications from the
* released version in the form of a patch file along with the binaries,
* 2. add special version identification to distinguish your version
* in addition to the base release version number,
* 3. provide your name and address as the primary contact for the
* support of your modified version, and
* 4. retain our contact information in regard to use of the base
* software.
* Permission to distribute the released version of the source code along
* with corresponding source modifications in the form of a patch file is
* granted with same provisions 2 through 4 for binary distributions.
*
* This software is provided "as is" without express or implied warranty
* to the extent permitted by applicable law.
]*/
/*
* This file is included by ../term.c.
*
* This terminal driver supports:
* SVGA up to 1024x768x256 for PC's running the Linux Operating System
* (also VGA 640x480x16, and SVGA 800x600x256)
*
* AUTHOR
* Scott Heavner (sdh@po.cwru.edu)
* based on original linux.trm by Tommy Frandsen (frandsen@diku.dk)
* patched by David J. Liu (liu@molecule.phri.nyu.edu)
* to increase perfomance and safety based on the features of SVGALib/GL.
* send your comments or suggestions to (pixar!info-gnuplot@sun.com).
*/
/*
* Compile with Linux SVGAlib 0.95 currently maintained by
* Harm Hanemaayer (hhanemaa@cs.ruu.nl).
* supports Trident, Tseng, Cirrus, Oak and generic vga.
*/
#include "driver.h"
/*
* January 2012 (Gnuplot version 4.6)
* This font used to be imported from bitmap.c, which is no longer built
* by default.
*/
#ifndef FNT5X9
#define FNT5X9 0
#define FNT5X9_VCHAR 11 /* vertical spacing between characters */
#define FNT5X9_VBITS 9 /* actual number of rows of bits per char */
#define FNT5X9_HCHAR 7 /* horizontal spacing between characters */
#define FNT5X9_HBITS 5 /* actual number of bits per row per char */
#ifndef TERM_HELP
/* 5x9 font, bottom row first, left pixel in lsb */
const unsigned int fnt5x9[96][FNT5X9_VBITS] = {
/* */ {000000,000000,000000,000000,000000,000000,000000,000000,000000},
/*!*/ {000000,000000,0x0004,000000,0x0004,0x0004,0x0004,0x0004,0x0004},
/*"*/ {000000,000000,000000,000000,000000,000000,0x000a,0x000a,0x000a},
/*#*/ {000000,000000,0x000a,0x000a,0x001f,0x000a,0x001f,0x000a,0x000a},
/*$*/ {000000,000000,0x0004,0x000f,0x0014,0x000e,0x0005,0x001e,0x0004},
/*%*/ {000000,000000,0x0018,0x0019,0x0002,0x0004,0x0008,0x0013,0x0003},
/*&*/ {000000,000000,0x0016,0x0009,0x0015,0x0002,0x0005,0x0005,0x0002},
/*'*/ {000000,000000,000000,000000,000000,0x0002,0x0004,0x0006,0x0006},
/*(*/ {000000,000000,0x0008,0x0004,0x0002,0x0002,0x0002,0x0004,0x0008},
/*)*/ {000000,000000,0x0002,0x0004,0x0008,0x0008,0x0008,0x0004,0x0002},
/***/ {000000,000000,0x0004,0x0015,0x000e,0x001f,0x000e,0x0015,0x0004},
/*+*/ {000000,000000,000000,0x0004,0x0004,0x001f,0x0004,0x0004,000000},
/*,*/ {000000,0x0002,0x0004,0x0006,0x0006,000000,000000,000000,000000},
/*-*/ {000000,000000,000000,000000,000000,0x001f,000000,000000,000000},
/*.*/ {000000,000000,0x0006,0x0006,000000,000000,000000,000000,000000},
/*-/-*/{000000,000000,000000,0x0001,0x0002,0x0004,0x0008,0x0010,000000},
/*0*/ {000000,000000,0x000e,0x0011,0x0013,0x0015,0x0019,0x0011,0x000e},
/*1*/ {000000,000000,0x000e,0x0004,0x0004,0x0004,0x0004,0x0006,0x0004},
/*2*/ {000000,000000,0x001f,0x0001,0x0001,0x000e,0x0010,0x0011,0x000e},
/*3*/ {000000,000000,0x000e,0x0011,0x0010,0x000c,0x0010,0x0011,0x000e},
/*4*/ {000000,000000,0x0008,0x0008,0x001f,0x0009,0x000a,0x000c,0x0008},
/*5*/ {000000,000000,0x000e,0x0011,0x0010,0x0010,0x000f,0x0001,0x001f},
/*6*/ {000000,000000,0x000e,0x0011,0x0011,0x000f,0x0001,0x0002,0x000c},
/*7*/ {000000,000000,0x0001,0x0001,0x0002,0x0004,0x0008,0x0010,0x001f},
/*8*/ {000000,000000,0x000e,0x0011,0x0011,0x000e,0x0011,0x0011,0x000e},
/*9*/ {000000,000000,0x0006,0x0008,0x0010,0x001e,0x0011,0x0011,0x000e},
/*:*/ {000000,000000,000000,0x0006,0x0006,000000,0x0006,0x0006,000000},
/*;*/ {000000,0x0001,0x0002,0x0006,0x0006,000000,0x0006,0x0006,000000},
/*<*/ {000000,000000,0x0008,0x0004,0x0002,0x0001,0x0002,0x0004,0x0008},
/*=*/ {000000,000000,000000,000000,0x001f,000000,0x001f,000000,000000},
/*>*/ {000000,000000,0x0002,0x0004,0x0008,0x0010,0x0008,0x0004,0x0002},
/*?*/ {000000,000000,0x0004,000000,0x0004,0x0008,0x0010,0x0011,0x000e},
/*@*/ {000000,000000,0x000e,0x0015,0x0015,0x0016,0x0010,0x0011,0x000e},
/*A*/ {000000,000000,0x0011,0x0011,0x001f,0x0011,0x0011,0x000a,0x0004},
/*B*/ {000000,000000,0x000f,0x0012,0x0012,0x000e,0x0012,0x0012,0x000f},
/*C*/ {000000,000000,0x000e,0x0011,0x0001,0x0001,0x0001,0x0011,0x000e},
/*D*/ {000000,000000,0x000f,0x0012,0x0012,0x0012,0x0012,0x0012,0x000f},
/*E*/ {000000,000000,0x001f,0x0001,0x0001,0x0007,0x0001,0x0001,0x001f},
/*F*/ {000000,000000,0x0001,0x0001,0x0001,0x0007,0x0001,0x0001,0x001f},
/*G*/ {000000,000000,0x001e,0x0011,0x0011,0x0019,0x0001,0x0001,0x001e},
/*H*/ {000000,000000,0x0011,0x0011,0x0011,0x001f,0x0011,0x0011,0x0011},
/*I*/ {000000,000000,0x000e,0x0004,0x0004,0x0004,0x0004,0x0004,0x000e},
/*J*/ {000000,000000,0x000e,0x0011,0x0010,0x0010,0x0010,0x0010,0x0010},
/*K*/ {000000,000000,0x0011,0x0009,0x0005,0x0003,0x0005,0x0009,0x0011},
/*L*/ {000000,000000,0x001f,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001},
/*M*/ {000000,000000,0x0011,0x0011,0x0011,0x0015,0x0015,0x001b,0x0011},
/*N*/ {000000,000000,0x0011,0x0011,0x0011,0x0019,0x0015,0x0013,0x0011},
/*O*/ {000000,000000,0x000e,0x0011,0x0011,0x0011,0x0011,0x0011,0x000e},
/*P*/ {000000,000000,0x0001,0x0001,0x0001,0x000f,0x0011,0x0011,0x000f},
/*Q*/ {000000,0x0018,0x000e,0x0015,0x0011,0x0011,0x0011,0x0011,0x000e},
/*R*/ {000000,000000,0x0011,0x0009,0x0005,0x000f,0x0011,0x0011,0x000f},
/*S*/ {000000,000000,0x000e,0x0011,0x0010,0x000e,0x0001,0x0011,0x000e},
/*T*/ {000000,000000,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x001f},
/*U*/ {000000,000000,0x000e,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011},
/*V*/ {000000,000000,0x0004,0x0004,0x000a,0x000a,0x0011,0x0011,0x0011},
/*W*/ {000000,000000,0x0011,0x001b,0x0015,0x0011,0x0011,0x0011,0x0011},
/*X*/ {000000,000000,0x0011,0x0011,0x000a,0x0004,0x000a,0x0011,0x0011},
/*Y*/ {000000,000000,0x0004,0x0004,0x0004,0x0004,0x000a,0x0011,0x0011},
/*Z*/ {000000,000000,0x001f,0x0001,0x0002,0x0004,0x0008,0x0010,0x001f},
/*[*/ {000000,000000,0x000e,0x0002,0x0002,0x0002,0x0002,0x0002,0x000e},
/*\ */ {000000,000000,000000,0x0010,0x0008,0x0004,0x0002,0x0001,000000},
/*]*/ {000000,000000,0x000e,0x0008,0x0008,0x0008,0x0008,0x0008,0x000e},
/*^*/ {000000,000000,000000,000000,000000,000000,0x0011,0x000a,0x0004},
/*_*/ {000000,000000,0x001f,000000,000000,000000,000000,000000,000000},
/*`*/ {000000,000000,000000,000000,000000,0x0008,0x0004,0x000c,0x000c},
/*a*/ {000000,000000,0x001e,0x0011,0x001e,0x0010,0x000e,000000,000000},
/*b*/ {000000,000000,0x000d,0x0013,0x0011,0x0013,0x000d,0x0001,0x0001},
/*c*/ {000000,000000,0x000e,0x0011,0x0001,0x0011,0x000e,000000,000000},
/*d*/ {000000,000000,0x0016,0x0019,0x0011,0x0019,0x0016,0x0010,0x0010},
/*e*/ {000000,000000,0x000e,0x0001,0x001f,0x0011,0x000e,000000,000000},
/*f*/ {000000,000000,0x0004,0x0004,0x0004,0x000e,0x0004,0x0014,0x0008},
/*g*/ {0x000e,0x0011,0x0016,0x0019,0x0011,0x0019,0x0016,000000,000000},
/*h*/ {000000,000000,0x0011,0x0011,0x0011,0x0013,0x000d,0x0001,0x0001},
/*i*/ {000000,000000,0x000e,0x0004,0x0004,0x0004,0x0006,000000,0x0004},
/*j*/ {0x0006,0x0009,0x0008,0x0008,0x0008,0x0008,0x000c,000000,0x0008},
/*k*/ {000000,000000,0x0009,0x0005,0x0003,0x0005,0x0009,0x0001,0x0001},
/*l*/ {000000,000000,0x000e,0x0004,0x0004,0x0004,0x0004,0x0004,0x0006},
/*m*/ {000000,000000,0x0015,0x0015,0x0015,0x0015,0x000b,000000,000000},
/*n*/ {000000,000000,0x0011,0x0011,0x0011,0x0013,0x000d,000000,000000},
/*o*/ {000000,000000,0x000e,0x0011,0x0011,0x0011,0x000e,000000,000000},
/*p*/ {0x0001,0x0001,0x000d,0x0013,0x0011,0x0013,0x000d,000000,000000},
/*q*/ {0x0010,0x0010,0x0016,0x0019,0x0011,0x0019,0x0016,000000,000000},
/*r*/ {000000,000000,0x0001,0x0001,0x0001,0x0013,0x000d,000000,000000},
/*s*/ {000000,000000,0x000f,0x0010,0x000e,0x0001,0x001e,000000,000000},
/*t*/ {000000,000000,0x0008,0x0014,0x0004,0x0004,0x001f,0x0004,0x0004},
/*u*/ {000000,000000,0x0016,0x0019,0x0011,0x0011,0x0011,000000,000000},
/*v*/ {000000,000000,0x0004,0x000a,0x0011,0x0011,0x0011,000000,000000},
/*w*/ {000000,000000,0x000a,0x0015,0x0015,0x0011,0x0011,000000,000000},
/*x*/ {000000,000000,0x0011,0x000a,0x0004,0x000a,0x0011,000000,000000},
/*y*/ {0x000e,0x0010,0x001e,0x0011,0x0011,0x0011,0x0011,000000,000000},
/*z*/ {000000,000000,0x001f,0x0002,0x0004,0x0008,0x001f,000000,000000},
/*{*/ {000000,000000,0x0008,0x0004,0x0004,0x0002,0x0004,0x0004,0x0008},
/*|*/ {000000,000000,0x0004,0x0004,0x0004,000000,0x0004,0x0004,0x0004},
/*}*/ {000000,000000,0x0002,0x0004,0x0004,0x0008,0x0004,0x0004,0x0002},
/*~*/ {000000,000000,000000,000000,000000,000000,0x0008,0x0015,0x0002},
/*DEL*/{000000,000000,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f,0x001f},
};
#endif /* TERM_HELP */
#endif /* local copy of 5x9 font */
#ifdef TERM_REGISTER
register_term(linux)
#endif
#ifdef TERM_PROTO
#define LINUX_VCHAR FNT5X9_VCHAR
#define LINUX_HCHAR FNT5X9_HCHAR
#define LINUX_VTIC 5
#define LINUX_HTIC 5
#define LINUX_XMAX 0 /* These two entries are just place holders. */
#define LINUX_YMAX 0 /* The actual values will be filled in init. */
TERM_PUBLIC void LINUX_options __PROTO((void));
TERM_PUBLIC void LINUX_init __PROTO((void));
TERM_PUBLIC void LINUX_reset __PROTO((void));
TERM_PUBLIC void LINUX_text __PROTO((void));
TERM_PUBLIC void LINUX_graphics __PROTO((void));
TERM_PUBLIC void LINUX_linetype __PROTO((int linetype));
TERM_PUBLIC void LINUX_move __PROTO((unsigned int x, unsigned int y));
TERM_PUBLIC void LINUX_vector __PROTO((unsigned int x, unsigned int y));
TERM_PUBLIC int LINUX_text_angle __PROTO((int ang));
TERM_PUBLIC void LINUX_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
TERM_PUBLIC void LINUX_suspend __PROTO((void));
TERM_PUBLIC void LINUX_resume __PROTO((void));
/* also used in vgagl.trm, so export it: */
TERM_PUBLIC int LINUX_graphics_allowed;
#endif
#ifdef TERM_BODY
#define _STRING_H_
#include <vga.h>
static int linux_vmode = G1024x768x256; /* default mode */
static int vgacolor[] = { 7, 8, 2, 3, 4, 5, 9, 14, 12, 15, 13, 10, 11, 1, 6 };
static int graphics_on = FALSE;
static vga_modeinfo *modeinfo;
static int linux_startx, linux_starty, linux_lasty;
static int linux_angle;
TERM_PUBLIC int LINUX_graphics_allowed = FALSE; /* also used in vgagl.trm */
extern void drop_privilege __PROTO((void));
extern void take_privilege __PROTO((void));
typedef int (*linux_line_func_ptr) __PROTO((int x1, int y1, int x2, int y2));
static void LINUX_putc __PROTO((unsigned int x, unsigned int y, int c, int ang,
linux_line_func_ptr line_func));
/* this function is called at the very beginning of main() to initialize
* the vgalib and to revoke suid privileges.
* /dev/console and /dev/tty\d and /dev/vc/\d are considered graphic terminals, all other
* don't support the linux terminal */
void
LINUX_setup()
{
char line[256];
FILE *pipe;
LINUX_graphics_allowed = FALSE;
if (geteuid() != 0)
return; /* if we aren't root, we cannot init graphics */
if ((pipe = popen("/usr/bin/tty", "r")) != NULL) {
line[0] = 0;
fgets(line, 256, pipe);
pclose(pipe);
line[strlen(line) - 1] = '\0';
if (
strcmp(line, "/dev/console") == 0 ||
( ( strncmp(line, "/dev/tty", 8) == 0 || strncmp(line, "/dev/vc/", 8) == 0 )
&& isdigit((unsigned char) line[8]))
) {
LINUX_graphics_allowed = TRUE;
} else {
/* check for socket name as set for example by `screen' */
char* sty = getenv("STY");
if (sty) {
int n1, n2;
if (3 == sscanf(sty, "%d.tty%d.%s", &n1, &n2, line)) {
/* we could check here, if host is the
* same as gethostname() returns. */
LINUX_graphics_allowed = TRUE;
}
}
}
}
if (LINUX_graphics_allowed) {
take_privilege();
vga_init();
drop_privilege();
} else {
/* err - shouldn't we give up root uid whatever happens ?
* or perhaps vga_init() does it ?
*/
setuid(getuid());
}
}
TERM_PUBLIC
void LINUX_options()
{
if (!LINUX_graphics_allowed) {
int_error(NO_CARET, "Linux terminal driver not available");
}
fprintf(stderr, "%s\n", vga_getmodename(linux_vmode));
}
TERM_PUBLIC
void LINUX_init()
{
/* vga_init () has been moved to immediately after main () for security */
if (vga_getdefaultmode() != -1)
linux_vmode = vga_getdefaultmode();
/* get the default mode from GSVGAMODE, if available */
if (!vga_hasmode(linux_vmode))
linux_vmode = G640x480x16;
/* test default mode first */
if (!vga_hasmode(linux_vmode)) {
fputs("Error, unable to initiate graphics.\n", stderr);
return;
} /* this mode is the bottom line */
modeinfo = vga_getmodeinfo(linux_vmode);
term->xmax = modeinfo->width;
term->ymax = modeinfo->height;
linux_lasty = modeinfo->height - 1;
}
TERM_PUBLIC void
LINUX_reset()
{
if (graphics_on) {
vga_setmode(TEXT);
graphics_on = FALSE;
}
}
TERM_PUBLIC void
LINUX_text()
{
if (graphics_on) {
vga_getch();
vga_setmode(TEXT);
graphics_on = FALSE;
}
}
TERM_PUBLIC void
LINUX_graphics()
{
if (!graphics_on) {
vga_setmode(linux_vmode);
graphics_on = TRUE;
}
}
TERM_PUBLIC void
LINUX_suspend()
{
vga_flip();
}
TERM_PUBLIC void
LINUX_resume()
{
vga_flip();
}
TERM_PUBLIC void
LINUX_linetype(int linetype)
{
if (linetype < -2)
linetype = LT_BLACK;
if (linetype >= 13)
linetype %= 13;
vga_setegacolor(vgacolor[linetype + 2]);
}
TERM_PUBLIC void
LINUX_move(unsigned int x, unsigned int y)
{
linux_startx = x;
linux_starty = y;
}
TERM_PUBLIC void
LINUX_vector(unsigned int x, unsigned int y)
{
vga_drawline(linux_startx, linux_lasty - linux_starty, x, linux_lasty - y);
linux_startx = x;
linux_starty = y;
}
TERM_PUBLIC int
LINUX_text_angle(int ang)
{
linux_angle = (ang ? 1 : 0);
return TRUE;
}
static void
LINUX_putc(
unsigned int x, unsigned int y,
int c,
int ang,
linux_line_func_ptr line_func)
{
int i, j, k;
unsigned int pixelon;
i = (int) (c) - 32;
for (j = 0; j < FNT5X9_VBITS; j++) {
for (k = 0; k < FNT5X9_HBITS; k++) {
pixelon = (((unsigned int) (fnt5x9[i][j])) >> k & 1);
if (pixelon) {
switch (ang) {
case 0:
(*line_func) (x + k + 1, y - j, x + k + 1, y - j);
break;
case 1:
(*line_func) (x - j, y - k - 1, x - j, y - k - 1);
break;
}
}
}
}
}
TERM_PUBLIC void
LINUX_put_text(unsigned int x, unsigned int y, const char *str)
{
int i;
switch (linux_angle) {
case 0:
y -= LINUX_VCHAR / 2;
break;
case 1:
x += LINUX_VCHAR / 2;
break;
}
for (i = 0; str[i]; i++) {
LINUX_putc(x, linux_lasty - y, str[i], linux_angle, vga_drawline);
switch (linux_angle) {
case 0:
x += LINUX_HCHAR;
break;
case 1:
y += LINUX_HCHAR;
break;
}
}
}
#endif
#ifdef TERM_TABLE
TERM_TABLE_START(linux_driver)
"linux", "Linux PC with (s)vgalib",
LINUX_XMAX, LINUX_YMAX, LINUX_VCHAR, LINUX_HCHAR,
LINUX_VTIC, LINUX_HTIC, LINUX_options, LINUX_init, LINUX_reset,
LINUX_text, null_scale, LINUX_graphics, LINUX_move, LINUX_vector,
LINUX_linetype, LINUX_put_text, LINUX_text_angle,
null_justify_text, do_point, do_arrow, set_font_null,
0, /* pointsize */
TERM_CAN_MULTIPLOT, LINUX_suspend, LINUX_resume
TERM_TABLE_END(linux_driver)
#undef LAST_TERM
#define LAST_TERM linux_driver
#endif
#ifdef TERM_HELP
START_HELP(linux)
"1 linux",
"?commands set terminal linux",
"?set terminal linux",
"?set term linux",
"?terminal linux",
"?term linux",
"?linux",
" The `linux` driver has no additional options to specify. It looks at the",
" environment variable GSVGAMODE for the default mode; if not set, it uses",
" 1024x768x256 as default mode or, if that is not possible, 640x480x16",
" (standard VGA)."
END_HELP(linux)
#endif