/* Hello, Emacs, this is -*-C-*- * $Id: dumb.trm,v 1.26.2.1 2008/08/16 18:11:53 sfeam Exp $ * */ /* GNUPLOT - dumb.trm */ /*[ * Copyright 1991 - 1993, 1998, 2004 Thomas Williams, Colin Kelley * * 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: * DUMB terminals * * AUTHORS * Francois Pinard, 91-04-03 * INTERNET: pinard@iro.umontreal.ca * * Ethan A Merritt Nov 2003 * Added support for enhanced text mode. * Yes, this is frivolous, but it serves as an example for * adding enhanced text to other terminals. You can disable * it by adding a line * #define NO_DUMB_ENHANCED_SUPPORT * * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net). * */ #include "driver.h" #ifdef TERM_REGISTER register_term(dumb_driver) #endif #ifdef TERM_PROTO TERM_PUBLIC void DUMB_options __PROTO((void)); TERM_PUBLIC void DUMB_init __PROTO((void)); TERM_PUBLIC void DUMB_graphics __PROTO((void)); TERM_PUBLIC void DUMB_text __PROTO((void)); TERM_PUBLIC void DUMB_reset __PROTO((void)); TERM_PUBLIC void DUMB_linetype __PROTO((int linetype)); TERM_PUBLIC void DUMB_move __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void DUMB_point __PROTO((unsigned int x, unsigned int y, int point)); TERM_PUBLIC void DUMB_vector __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void DUMB_put_text __PROTO((unsigned int x, unsigned int y, const char *str)); TERM_PUBLIC void DUMB_arrow __PROTO((unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head)); #ifndef NO_DUMB_ENHANCED_SUPPORT /* To support "set term dumb enhanced" (don't ask why!) */ TERM_PUBLIC void ENHdumb_put_text __PROTO((unsigned int x, unsigned int y, const char str[])); TERM_PUBLIC void ENHdumb_OPEN __PROTO((char * fontname, double fontsize, double base, TBOOLEAN widthflag, TBOOLEAN showflag, int overprint)); TERM_PUBLIC void ENHdumb_FLUSH __PROTO((void)); #else #define ENHdumb_put_text NULL #endif #define DUMB_XMAX 79 #define DUMB_YMAX 24 #endif /* TERM_PROTO */ #ifdef TERM_BODY #define DUMB_AXIS_CONST '\1' #define DUMB_BORDER_CONST '\2' /* matrix of characters */ static char *dumb_matrix = NULL; /* matrix of priority at each position */ static char *dumb_priority = NULL; /* current character used to draw */ static char dumb_pen; /* current X position */ static int dumb_x; /* current Y position */ static int dumb_y; static int dumb_xmax = DUMB_XMAX; static int dumb_ymax = DUMB_YMAX; static int dumb_feed = 1; #define DUMB_PIXEL(x,y) dumb_matrix[dumb_xmax*(y)+(x)] static void dumb_set_pixel __PROTO((int x, int y, int v, int p)); enum DUMB_id { DUMB_FEED, DUMB_NOFEED, DUMB_ENH, DUMB_NOENH, DUMB_SIZE, DUMB_OTHER }; static struct gen_table DUMB_opts[] = { { "f$eed", DUMB_FEED }, { "nof$eed", DUMB_NOFEED }, { "enh$anced", DUMB_ENH }, { "noe$nhanced", DUMB_NOENH }, { "size", DUMB_SIZE }, { NULL, DUMB_OTHER } }; TERM_PUBLIC void DUMB_options() { int x, y; struct value a; while (!END_OF_COMMAND) { switch(lookup_table(&DUMB_opts[0],c_token)) { case DUMB_FEED: c_token++; dumb_feed = 1; break; case DUMB_NOFEED: c_token++; dumb_feed = 0; break; #ifndef NO_DUMB_ENHANCED_SUPPORT case DUMB_ENH: c_token++; term->put_text = ENHdumb_put_text; term->flags |= TERM_ENHANCED_TEXT; break; case DUMB_NOENH: c_token++; term->put_text = DUMB_put_text; term->flags &= ~TERM_ENHANCED_TEXT; break; #endif case DUMB_SIZE: c_token++; /* Fall through */ case DUMB_OTHER: default: x = (int) real(const_express(&a)); if (!END_OF_COMMAND) { if (equals(c_token,",")) c_token++; y = (int) real(const_express(&a)); dumb_xmax = term->xmax = x; dumb_ymax = term->ymax = y; } break; } } sprintf(term_options, "%sfeed %s %d %d", dumb_feed ? "" : "no", term->put_text == ENHdumb_put_text ? "enhanced" : "", dumb_xmax, dumb_ymax); } static void dumb_set_pixel(int x, int y, int v, int p) { if ((unsigned) x <= dumb_xmax && /* ie x>=0 && x<=dumb_xmax */ (unsigned) y <= dumb_ymax && p > dumb_priority[dumb_xmax * y + x]) { dumb_matrix[dumb_xmax * y + x] = v; dumb_priority[dumb_xmax * y + x] = p; } } TERM_PUBLIC void DUMB_init() { if (dumb_matrix) free(dumb_matrix); dumb_matrix = gp_alloc((dumb_xmax+1) * (dumb_ymax+1) * 2, "dumb terminal"); dumb_priority = dumb_matrix + dumb_xmax * dumb_ymax; } TERM_PUBLIC void DUMB_graphics() { int i; char *pm = dumb_matrix, *pp = dumb_priority; for (i = dumb_xmax * dumb_ymax; i > 0; i--) { *pm++ = ' '; *pp++ = 0; } } TERM_PUBLIC void DUMB_text() { int x, y, l; putc('\f', gpoutfile); for (y = dumb_ymax - 1; y >= 0; y--) { for (l = dumb_xmax; l > 0 && DUMB_PIXEL(l - 1, y) == ' '; l--); for (x = 0; x < l; x++) putc(DUMB_PIXEL(x, y), gpoutfile); if (dumb_feed || y > 0) putc('\n', gpoutfile); } fflush(gpoutfile); } TERM_PUBLIC void DUMB_reset() { if (dumb_matrix) free(dumb_matrix); dumb_matrix = NULL; } TERM_PUBLIC void DUMB_linetype(int linetype) { static char pen_type[7] = { '*', '#', '$', '%', '@', '&', '=' }; if (linetype == LT_BLACK) dumb_pen = DUMB_BORDER_CONST; else if (linetype == LT_AXIS) dumb_pen = DUMB_AXIS_CONST; else if (linetype <= LT_NODRAW) dumb_pen = ' '; else { linetype = linetype % 7; dumb_pen = pen_type[linetype]; } } TERM_PUBLIC void DUMB_move(unsigned int x, unsigned int y) { dumb_x = x; dumb_y = y; } TERM_PUBLIC void DUMB_point(unsigned int x, unsigned int y, int point) { dumb_set_pixel(x, y, point == -1 ? '.' : point % 26 + 'A', 4); } TERM_PUBLIC void DUMB_vector(unsigned int arg_x, unsigned int arg_y) { int x = arg_x; /* we need signed int, since * unsigned-signed=unsigned and */ int y = arg_y; /* abs and cast to double wouldn't work */ char pen, pen1; int priority; int delta; if (ABS(y - dumb_y) > ABS(x - dumb_x)) { switch (dumb_pen) { case DUMB_AXIS_CONST: pen = ':'; pen1 = '+'; priority = 1; break; case DUMB_BORDER_CONST: pen = '|'; pen1 = '+'; priority = 2; break; default: pen = dumb_pen; pen1 = dumb_pen; priority = 3; break; } dumb_set_pixel(dumb_x, dumb_y, pen1, priority); for (delta = 1; delta < ABS(y - dumb_y); delta++) { dumb_set_pixel(dumb_x + (int) ((double) (x - dumb_x) * delta / ABS(y - dumb_y) + 0.5), dumb_y + delta * sign(y - dumb_y), pen, priority); } dumb_set_pixel(x, y, pen1, priority); } else if (ABS(x - dumb_x) > ABS(y - dumb_y)) { switch (dumb_pen) { case DUMB_AXIS_CONST: pen = '.'; pen1 = '+'; priority = 1; break; case DUMB_BORDER_CONST: pen = '-'; pen1 = '+'; priority = 2; break; default: pen = dumb_pen; pen1 = dumb_pen; priority = 3; break; } dumb_set_pixel(dumb_x, dumb_y, pen1, priority); for (delta = 1; delta < ABS(x - dumb_x); delta++) dumb_set_pixel(dumb_x + delta * sign(x - dumb_x), dumb_y + (int) ((double) (y - dumb_y) * delta / ABS(x - dumb_x) + 0.5), pen, priority); dumb_set_pixel(x, y, pen1, priority); } else { switch (dumb_pen) { case DUMB_AXIS_CONST: /* zero length axis */ pen = '+'; priority = 1; break; case DUMB_BORDER_CONST: /* zero length border */ pen = '+'; priority = 2; break; default: pen = dumb_pen; priority = 3; break; } for (delta = 0; delta <= ABS(x - dumb_x); delta++) dumb_set_pixel(dumb_x + delta * sign(x - dumb_x), dumb_y + delta * sign(y - dumb_y), pen, priority); } dumb_x = x; dumb_y = y; } TERM_PUBLIC void DUMB_put_text(unsigned int x, unsigned int y, const char *str) { int length; length = strlen(str); if (x + length > dumb_xmax) x = GPMAX(0, dumb_xmax - length); for (; x < dumb_xmax && *str; x++, str++) dumb_set_pixel(x, y, *str, 5); } TERM_PUBLIC void DUMB_arrow( unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head) /* ignored */ { char saved_pen; char saved_x; char saved_y; (void) head; /* dummy usage avoid compiler warnings */ saved_pen = dumb_pen; saved_x = dumb_x; saved_y = dumb_y; dumb_pen = '>'; dumb_x = sx; dumb_y = sy; DUMB_vector(ex, ey); dumb_pen = saved_pen; dumb_x = saved_x; dumb_y = saved_y; } #ifndef NO_DUMB_ENHANCED_SUPPORT /* * The code from here on serves as an example of how to * add enhanced text mode support to even a dumb driver. */ static TBOOLEAN ENHdumb_opened_string; static TBOOLEAN ENHdumb_show = TRUE; static int ENHdumb_overprint = 0; static TBOOLEAN ENHdumb_widthflag = TRUE; static unsigned int ENHdumb_xsave, ENHdumb_ysave; #define ENHdumb_fontsize 1 #define ENHdumb_font "" static double ENHdumb_base; TERM_PUBLIC void ENHdumb_OPEN( char *fontname, double fontsize, double base, TBOOLEAN widthflag, TBOOLEAN showflag, int overprint) { /* There are two special cases: * overprint = 3 means save current position * overprint = 4 means restore saved position */ if (overprint == 3) { ENHdumb_xsave = dumb_x; ENHdumb_ysave = dumb_y; return; } else if (overprint == 4) { DUMB_move(ENHdumb_xsave, ENHdumb_ysave); return; } if (!ENHdumb_opened_string) { ENHdumb_opened_string = TRUE; /* Start new text fragment */ enhanced_cur_text = &enhanced_text[0]; /* Scale fractional font height to vertical units of display */ ENHdumb_base = base * 2; /* Keep track of whether we are supposed to show this string */ ENHdumb_show = showflag; /* 0/1/2 no overprint / 1st pass / 2nd pass */ ENHdumb_overprint = overprint; /* widthflag FALSE means do not update text position after printing */ ENHdumb_widthflag = widthflag; /* Many drivers will need to do something about font selection here */ /* but dumb is dumb */ } } TERM_PUBLIC void ENHdumb_FLUSH() { char *str = enhanced_text; /* The fragment to print */ int x = dumb_x; /* The current position */ int len; if (ENHdumb_opened_string) { *enhanced_cur_text = '\0'; len = strlen(str); /* print the string fragment, perhaps invisibly */ /* NB: base expresses offset from current y pos */ for (; x < dumb_xmax && *str; x++, str++) if (ENHdumb_show) dumb_set_pixel(x, dumb_y+ENHdumb_base, *str, 5); if (!ENHdumb_widthflag) /* don't update position */ ; else if (ENHdumb_overprint == 1) /* First pass of overprint, leave position in center of fragment */ dumb_x += len / 2; else /* Normal case is to update position to end of fragment */ dumb_x += len; ENHdumb_opened_string = FALSE; } } TERM_PUBLIC void ENHdumb_put_text(unsigned int x, unsigned int y, const char *str) { /* If no enhanced text processing is needed, we can use the plain */ /* vanilla put_text() routine instead of this fancy recursive one. */ if (ignore_enhanced_text || !strpbrk(str, "{}^_@&~")) { DUMB_put_text(x,y,str); return; } /* Set up global variables needed by enhanced_recursion() */ enhanced_fontscale = 1.0; ENHdumb_opened_string = FALSE; strncpy(enhanced_escape_format,"%c",sizeof(enhanced_escape_format)); DUMB_move(x,y); /* Set the recursion going. We say to keep going until a * closing brace, but we don't really expect to find one. * If the return value is not the nul-terminator of the * string, that can only mean that we did find an unmatched * closing brace in the string. We increment past it (else * we get stuck in an infinite loop) and try again. */ while (*(str = enhanced_recursion((char *)str, TRUE, ENHdumb_font, ENHdumb_fontsize, 0.0, TRUE, TRUE, 0))) { (term->enhanced_flush)(); /* I think we can only get here if *str == '}' */ enh_err_check(str); if (!*++str) break; /* end of string */ /* else carry on and process the rest of the string */ } } #endif /* NO_DUMB_ENHANCED_SUPPORT */ #endif /* TERM_BODY */ #ifdef TERM_TABLE TERM_TABLE_START(dumb_driver) "dumb", "ascii art for anything that prints text", DUMB_XMAX, DUMB_YMAX, 1, 1, 1, 1, DUMB_options, DUMB_init, DUMB_reset, DUMB_text, null_scale, DUMB_graphics, DUMB_move, DUMB_vector, DUMB_linetype, DUMB_put_text, null_text_angle, null_justify_text, DUMB_point, DUMB_arrow, set_font_null, 0, /* pointsize */ TERM_CAN_MULTIPLOT, NULL, NULL, NULL, NULL #ifdef USE_MOUSE , NULL, NULL, NULL, NULL, NULL #endif , NULL, NULL, NULL, NULL #ifdef WITH_IMAGE , NULL #endif #ifndef NO_DUMB_ENHANCED_SUPPORT , ENHdumb_OPEN, ENHdumb_FLUSH, do_enh_writec #endif /* NO_DUMB_ENHANCED_SUPPORT */ TERM_TABLE_END(dumb_driver) #undef LAST_TERM #define LAST_TERM dumb_driver #endif /* TERM_TABLE */ #ifdef TERM_HELP START_HELP(dumb) "1 dumb", "?commands set terminal dumb", "?set terminal dumb", "?set term dumb", "?terminal dumb", "?term dumb", "?dumb", " The `dumb` terminal driver has an optional size specification and trailing", " linefeed control.", "", " Syntax:", " set terminal dumb {[no]feed} { }", #ifndef NO_DUMB_ENHANCED_SUPPORT " {[no]enhanced}", #endif "", " where and set the size of the dumb terminals. Default is", " 79 by 24. The last newline is printed only if `feed` is enabled.", "", " Examples:", " set term dumb nofeed", " set term dumb 79 49 # VGA screen---why would anyone do that?" END_HELP(dumb) #endif /* TERM_HELP */