ngspice/src/frontend/terminal.c

391 lines
7.5 KiB
C

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
$Id$
**********/
/*
* Routines to handle "more"d output. There are some serious system
* dependencies in here, and it isn't clear that versions of this stuff
* can be written for every possible machine...
*/
#include "ngspice.h"
#include "config.h"
#include <stdarg.h>
#ifdef HAVE_ASPRINTF
#ifdef HAVE_LIBIBERTY_H /* asprintf */
#include <libiberty.h>
#elif defined(__MINGW32__) || defined(__SUNPRO_C) /* we have asprintf, but not libiberty.h */
#include <stdarg.h>
extern int asprintf(char **out, const char *fmt, ...);
extern int vasprintf(char **out, const char *fmt, va_list ap);
#endif
#endif
#ifdef HAVE_SGTTY_H
#include <sgtty.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#if 0
/* Bad interaction with bool type in bool.h because curses also
defines this symbol. */
#ifdef HAVE_TERMCAP
#include <curses.h>
#include <term.h>
#endif
#endif
#ifdef HAVE_TERMCAP_H
#include <termcap.h>
#elif HAVE_NCURSES_TERMCAP_H
#include <ncurses/termcap.h>
#endif
#include <cpdefs.h>
#include "variable.h"
#include "terminal.h"
/* out_printf doesn't handle double arguments correctly, so we
sprintf into this buf and call out_send w/ it */
char out_pbuf[8*BSIZE_SP];
bool out_moremode = TRUE;
bool out_isatty = TRUE;
#ifndef TCL_MODULE
#ifdef HAVE_TERMCAP
static char *motion_chars;
static char *clear_chars;
static char *home_chars;
static char *cleol_chars;
#endif /* HAVE_TERMCAP */
#define DEF_SCRHEIGHT 24
#define DEF_SCRWIDTH 80
static int xsize, ysize;
static int xpos, ypos;
static bool noprint, nopause;
/* Start output... */
void
out_init(void)
{
#ifdef TIOCGWINSZ
struct winsize ws;
#endif
noprint = nopause = FALSE;
if (cp_getvar("nomoremode", CP_BOOL, NULL))
out_moremode = FALSE;
else
out_moremode = TRUE;
if (!out_moremode || !cp_interactive)
out_isatty = FALSE;
if (!out_isatty)
return;
xsize = ysize = 0;
/* Figure out the screen size. We try, in order, TIOCGSIZE,
* tgetent(), and cp_getvar(height). Default is 24 x 80.
*/
#ifdef TIOCGWINSZ
if (!xsize || !ysize) {
(void) ioctl(fileno(stdout), TIOCGWINSZ, (char *) &ws);
xsize = ws.ws_col;
ysize = ws.ws_row;
}
#endif
if (!xsize)
(void) cp_getvar("width", CP_NUM, (char *) &xsize);
if (!ysize)
(void) cp_getvar("height", CP_NUM, (char *) &ysize);
if (!xsize)
xsize = DEF_SCRWIDTH;
if (!ysize)
ysize = DEF_SCRHEIGHT;
ysize -= 2; /* Fudge room... */
xpos = ypos = 0;
return;
}
/* Putc may not be buffered (sp?), so we do it ourselves. */
static char staticbuf[BUFSIZ];
struct {
int count;
char *ptr;
} ourbuf = { BUFSIZ, staticbuf };
/* send buffer out */
void
outbufputc(void)
{
if (ourbuf.count != BUFSIZ) {
fputs(staticbuf, cp_out);
memset(staticbuf, 0, BUFSIZ-ourbuf.count);
ourbuf.count = BUFSIZ;
ourbuf.ptr = staticbuf;
}
}
static void
bufputc(char c)
{
if (--ourbuf.count >= 0) {
*ourbuf.ptr++ = c;
} else {
/* Flush and reset the buffer */
outbufputc();
/* and store the character. */
ourbuf.count--;
*ourbuf.ptr++ = c;
}
}
/* prompt for a return */
void
promptreturn(void)
{
char buf[16];
moe:
fprintf(cp_out,
"\n\t-- hit return for more, ? for help -- ");
if (!fgets(buf, 16, cp_in)) {
clearerr(cp_in);
*buf = 'q';
}
switch (*buf) {
case '\n':
break;
case 'q':
noprint = TRUE;
break;
case 'c':
nopause = TRUE;
break;
case ' ':
break;
case '?':
fprintf(cp_out,
"\nPossible responses:\n\
\t<cr> : Print another screenful\n\
\tq <cr> : Discard the rest of the output\n\
\tc <cr> : Continuously print the rest of the output\n\
\t? <cr> : Print this help message\n");
goto moe;
default:
fprintf(cp_out, "Character %d is no good\n", *buf);
goto moe;
}
}
/* Print a string to the output. If this would cause the screen to scroll,
* print "more".
*/
void
out_send(char *string)
{
if (noprint)
return;
if (!out_isatty || nopause) {
fputs(string, cp_out);
return;
}
while (*string) {
switch (*string) {
case '\n':
xpos = 0;
ypos++;
break;
case '\f':
ypos = ysize;
xpos = 0;
break;
case '\t':
xpos = xpos / 8 + 1;
xpos *= 8;
break;
default:
xpos++;
break;
}
while (xpos >= xsize) {
xpos -= xsize;
ypos++;
}
if (ypos >= ysize) {
outbufputc(); /* out goes buffer */
promptreturn();
(void) fflush(cp_out);
ypos = xpos = 0;
}
bufputc(*string); /* we need to buffer these */
string++;
}
(void) outbufputc();
return;
}
/* Printf some stuff using more mode. */
void
out_printf(char *fmt, ...)
{
#if defined(HAVE_ASPRINTF) /* seems the best solution */
char * tbuf;
va_list ap;
va_start (ap, fmt);
vasprintf(&tbuf, fmt, ap);
va_end (ap);
out_send(tbuf);
FREE(tbuf);
#elif defined(HAVE_SNPRINTF) /* the second best */
va_list ap;
va_start (ap, fmt);
vsnprintf(out_pbuf, sizeof(out_pbuf), fmt, ap);
va_end (ap);
out_send(out_pbuf);
#else /* guaranteed a bug for long messages */
va_list ap;
va_start (ap, fmt);
vsprintf(out_pbuf, fmt, ap);
va_end (ap);
out_send(out_pbuf);
#endif
return;
}
#ifdef HAVE_TERMCAP
static int
outfn(int c)
{
putc(c, stdout);
return c;
}
#endif /* HAVE_TERMCAP */
void
tcap_init(void)
{
char *s;
#ifdef HAVE_TERMCAP
char tbuf[1025];
static char buf2[100];
char *charbuf;
charbuf = buf2;
if ((s = getenv("TERM"))) {
if (tgetent(tbuf, s) != -1) {
xsize = tgetnum("co");
ysize = tgetnum("li");
if ((xsize <= 0) || (ysize <= 0))
xsize = ysize = 0;
clear_chars = (char *) tgetstr("cl", &charbuf);
motion_chars = (char *) tgetstr("cm", &charbuf);
home_chars = (char *) tgetstr("ho", &charbuf);
cleol_chars = (char *) tgetstr("ce", &charbuf);
}
}
#endif
if (!xsize) {
if ((s = getenv("COLS")))
xsize = atoi(s);
if (xsize <= 0)
xsize = 0;
}
if (!ysize) {
if ((s = getenv("LINES")))
ysize = atoi(s);
if (ysize <= 0)
ysize = 0;
}
}
void
term_clear(void)
{
#ifdef HAVE_TERMCAP
if (*clear_chars)
tputs(clear_chars, 1, outfn);
else
fputs("\n", stdout);
#endif
}
void
term_home(void)
{
#ifdef HAVE_TERMCAP
if (*home_chars)
tputs(home_chars, 1, outfn);
else if (*motion_chars)
tputs(tgoto(motion_chars, 1, 1), 1, outfn);
else
fputs("\n", stdout);
#endif
}
void
term_cleol(void)
{
#ifdef HAVE_TERMCAP
if (*cleol_chars)
tputs(cleol_chars, 1, outfn);
#endif
}
#else
void out_init(void) {}
void outbufputc(void) {}
void promptreturn(void) {}
void term_clear(void) {}
void term_home(void) {}
void term_cleol(void) {}
void tcap_init(void) {}
void out_send(char *string) {fprintf(cp_out,string);}
void
out_printf(char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
vfprintf(cp_out, fmt, ap);
va_end (ap);
}
#endif /* TCL_MODULE */