|
Packit |
992a25 |
/***********************************************************************
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* This software is part of the ast package *
|
|
Packit |
992a25 |
* Copyright (c) 1985-2011 AT&T Intellectual Property *
|
|
Packit |
992a25 |
* and is licensed under the *
|
|
Packit |
992a25 |
* Eclipse Public License, Version 1.0 *
|
|
Packit |
992a25 |
* by AT&T Intellectual Property *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* A copy of the License is available at *
|
|
Packit |
992a25 |
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
Packit |
992a25 |
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* Information and Software Systems Research *
|
|
Packit |
992a25 |
* AT&T Research *
|
|
Packit |
992a25 |
* Florham Park NJ *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* Glenn Fowler <gsf@research.att.com> *
|
|
Packit |
992a25 |
* David Korn <dgk@research.att.com> *
|
|
Packit |
992a25 |
* Phong Vo <kpv@research.att.com> *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
***********************************************************************/
|
|
Packit |
992a25 |
#include "sfdchdr.h"
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#if _PACKAGE_ast
|
|
Packit |
992a25 |
#include <ast_tty.h>
|
|
Packit |
992a25 |
#include <signal.h>
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/*
|
|
Packit |
992a25 |
* a simple but fast more style pager discipline
|
|
Packit |
992a25 |
* if on sfstdout then sfstdin ops reset the page state
|
|
Packit |
992a25 |
*
|
|
Packit |
992a25 |
* Glenn Fowler
|
|
Packit |
992a25 |
* AT&T Research
|
|
Packit |
992a25 |
*
|
|
Packit |
992a25 |
* @(#)$Id: sfdcmore (AT&T Research) 1998-06-25 $
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
typedef struct
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
Sfdisc_t disc; /* sfio discipline */
|
|
Packit |
992a25 |
Sfio_t* input; /* tied with this input stream */
|
|
Packit |
992a25 |
Sfio_t* error; /* tied with this error stream */
|
|
Packit |
992a25 |
int rows; /* max rows */
|
|
Packit |
992a25 |
int cols; /* max cols */
|
|
Packit |
992a25 |
int row; /* current row */
|
|
Packit |
992a25 |
int col; /* current col */
|
|
Packit |
992a25 |
int match; /* match length, 0 if none */
|
|
Packit |
992a25 |
char pattern[128]; /* match pattern */
|
|
Packit |
992a25 |
char prompt[1]; /* prompt string */
|
|
Packit |
992a25 |
} More_t;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/*
|
|
Packit |
992a25 |
* more read
|
|
Packit |
992a25 |
* we assume line-at-a-time input
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#if __STD_C
|
|
Packit |
992a25 |
static ssize_t moreread(Sfio_t* f, void* buf, size_t n, Sfdisc_t* dp)
|
|
Packit |
992a25 |
#else
|
|
Packit |
992a25 |
static ssize_t moreread(f, buf, n, dp)
|
|
Packit |
992a25 |
Sfio_t* f;
|
|
Packit |
992a25 |
void* buf;
|
|
Packit |
992a25 |
size_t n;
|
|
Packit |
992a25 |
Sfdisc_t* dp;
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
register More_t* more = (More_t*)dp;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
more->match = 0;
|
|
Packit |
992a25 |
more->row = 2;
|
|
Packit |
992a25 |
more->col = 1;
|
|
Packit |
992a25 |
return sfrd(f, buf, n, dp);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/*
|
|
Packit |
992a25 |
* output label on wfd and return next char on rfd with no echo
|
|
Packit |
992a25 |
* return < -1 is -(signal + 1)
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#if __STD_C
|
|
Packit |
992a25 |
static int ttyquery(Sfio_t* rp, Sfio_t* wp, const char* label, Sfdisc_t* dp)
|
|
Packit |
992a25 |
#else
|
|
Packit |
992a25 |
static int ttyquery(rp, wp, label, dp)
|
|
Packit |
992a25 |
Sfio_t* rp;
|
|
Packit |
992a25 |
Sfio_t* wp;
|
|
Packit |
992a25 |
char* label;
|
|
Packit |
992a25 |
Sfdisc_t* dp;
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
register int r;
|
|
Packit |
992a25 |
int n;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#ifdef TCSADRAIN
|
|
Packit |
992a25 |
unsigned char c;
|
|
Packit |
992a25 |
struct termios old;
|
|
Packit |
992a25 |
struct termios tty;
|
|
Packit |
992a25 |
int rfd = sffileno(rp);
|
|
Packit |
992a25 |
int wfd = sffileno(rp);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if (!label)
|
|
Packit |
992a25 |
n = 0;
|
|
Packit |
992a25 |
else if (n = strlen(label))
|
|
Packit |
992a25 |
write(wfd, label, n);
|
|
Packit |
992a25 |
tcgetattr(rfd, &old;;
|
|
Packit |
992a25 |
tty = old;
|
|
Packit |
992a25 |
tty.c_cc[VTIME] = 0;
|
|
Packit |
992a25 |
tty.c_cc[VMIN] = 1;
|
|
Packit |
992a25 |
tty.c_lflag &= ~(ICANON|ECHO|ECHOK|ISIG);
|
|
Packit |
992a25 |
tcsetattr(rfd, TCSADRAIN, &tty);
|
|
Packit |
992a25 |
if ((r = read(rfd, &c, 1)) == 1)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
if (c == old.c_cc[VEOF])
|
|
Packit |
992a25 |
r = -1;
|
|
Packit |
992a25 |
else if (c == old.c_cc[VINTR])
|
|
Packit |
992a25 |
r = -(SIGINT + 1);
|
|
Packit |
992a25 |
else if (c == old.c_cc[VQUIT])
|
|
Packit |
992a25 |
r = -(SIGQUIT + 1);
|
|
Packit |
992a25 |
else if (c == '\r')
|
|
Packit |
992a25 |
r = '\n';
|
|
Packit |
992a25 |
else
|
|
Packit |
992a25 |
r = c;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
tcsetattr(rfd, TCSADRAIN, &old;;
|
|
Packit |
992a25 |
if (n)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
write(wfd, "\r", 1);
|
|
Packit |
992a25 |
while (n-- > 0)
|
|
Packit |
992a25 |
write(wfd, " ", 1);
|
|
Packit |
992a25 |
write(wfd, "\r", 1);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
#else
|
|
Packit |
992a25 |
register char* s;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if (label && (n = strlen(label)))
|
|
Packit |
992a25 |
sfwr(wp, label, n, dp);
|
|
Packit |
992a25 |
r = (s = sfgetr(rp, '\n', 0)) ? *s : -1;
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
return r;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/*
|
|
Packit |
992a25 |
* more write
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#if __STD_C
|
|
Packit |
992a25 |
static ssize_t morewrite(Sfio_t* f, const Void_t* buf, register size_t n, Sfdisc_t* dp)
|
|
Packit |
992a25 |
#else
|
|
Packit |
992a25 |
static ssize_t morewrite(f, buf, n, dp)
|
|
Packit |
992a25 |
Sfio_t* f;
|
|
Packit |
992a25 |
Void_t* buf;
|
|
Packit |
992a25 |
register size_t n;
|
|
Packit |
992a25 |
Sfdisc_t* dp;
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
register More_t* more = (More_t*)dp;
|
|
Packit |
992a25 |
register char* b;
|
|
Packit |
992a25 |
register char* s;
|
|
Packit |
992a25 |
register char* e;
|
|
Packit |
992a25 |
register ssize_t w;
|
|
Packit |
992a25 |
register int r;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if (!more->row)
|
|
Packit |
992a25 |
return n;
|
|
Packit |
992a25 |
if (!more->col)
|
|
Packit |
992a25 |
return sfwr(f, buf, n, dp);
|
|
Packit |
992a25 |
w = 0;
|
|
Packit |
992a25 |
b = (char*)buf;
|
|
Packit |
992a25 |
s = b;
|
|
Packit |
992a25 |
e = s + n;
|
|
Packit |
992a25 |
if (more->match)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
match:
|
|
Packit |
992a25 |
for (r = more->pattern[0];; s++)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
if (s >= e)
|
|
Packit |
992a25 |
return n;
|
|
Packit |
992a25 |
if (*s == '\n')
|
|
Packit |
992a25 |
b = s + 1;
|
|
Packit |
992a25 |
else if (*s == r && (e - s) >= more->match && !strncmp(s, more->pattern, more->match))
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
s = b;
|
|
Packit |
992a25 |
w += b - (char*)buf;
|
|
Packit |
992a25 |
more->match = 0;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
while (s < e)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
switch (*s++)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
case '\t':
|
|
Packit |
992a25 |
more->col = ((more->col + 8) & ~7) - 1;
|
|
Packit |
992a25 |
/*FALLTHROUGH*/
|
|
Packit |
992a25 |
default:
|
|
Packit |
992a25 |
if (++more->col <= more->cols || s < e && *s == '\n')
|
|
Packit |
992a25 |
continue;
|
|
Packit |
992a25 |
/*FALLTHROUGH*/
|
|
Packit |
992a25 |
case '\n':
|
|
Packit |
992a25 |
more->col = 1;
|
|
Packit |
992a25 |
if (++more->row < more->rows)
|
|
Packit |
992a25 |
continue;
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
case '\b':
|
|
Packit |
992a25 |
if (more->col > 1)
|
|
Packit |
992a25 |
more->col--;
|
|
Packit |
992a25 |
continue;
|
|
Packit |
992a25 |
case '\r':
|
|
Packit |
992a25 |
more->col = 1;
|
|
Packit |
992a25 |
continue;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
w += sfwr(f, b, s - b, dp);
|
|
Packit |
992a25 |
b = s;
|
|
Packit |
992a25 |
r = ttyquery(sfstdin, f, more->prompt, dp);
|
|
Packit |
992a25 |
if (r == '/' || r == 'n')
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
if (r == '/')
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
sfwr(f, "/", 1, dp);
|
|
Packit |
992a25 |
if ((s = sfgetr(sfstdin, '\n', 1)) && (n = sfvalue(sfstdin) - 1) > 0)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
if (n >= sizeof(more->pattern))
|
|
Packit |
992a25 |
n = sizeof(more->pattern) - 1;
|
|
Packit |
992a25 |
memcpy(more->pattern, s, n);
|
|
Packit |
992a25 |
more->pattern[n] = 0;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
if (more->match = strlen(more->pattern))
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
more->row = 1;
|
|
Packit |
992a25 |
more->col = 1;
|
|
Packit |
992a25 |
goto match;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
switch (r)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
case '\n':
|
|
Packit |
992a25 |
case '\r':
|
|
Packit |
992a25 |
more->row--;
|
|
Packit |
992a25 |
more->col = 1;
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
case ' ':
|
|
Packit |
992a25 |
more->row = 2;
|
|
Packit |
992a25 |
more->col = 1;
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
default:
|
|
Packit |
992a25 |
more->row = 0;
|
|
Packit |
992a25 |
return n;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
if (s > b)
|
|
Packit |
992a25 |
w += sfwr(f, b, s - b, dp);
|
|
Packit |
992a25 |
return w;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/*
|
|
Packit |
992a25 |
* remove the discipline on close
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#if __STD_C
|
|
Packit |
992a25 |
static int moreexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* dp)
|
|
Packit |
992a25 |
#else
|
|
Packit |
992a25 |
static int moreexcept(f, type, data, dp)
|
|
Packit |
992a25 |
Sfio_t* f;
|
|
Packit |
992a25 |
int type;
|
|
Packit |
992a25 |
Void_t* data;
|
|
Packit |
992a25 |
Sfdisc_t* dp;
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
register More_t* more = (More_t*)dp;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if (type == SF_FINAL || type == SF_DPOP)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
if (f = more->input)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
more->input = 0;
|
|
Packit |
992a25 |
sfdisc(f, SF_POPDISC);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else if (f = more->error)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
more->error = 0;
|
|
Packit |
992a25 |
sfdisc(f, SF_POPDISC);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else
|
|
Packit |
992a25 |
free(dp);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else if (type == SF_SYNC)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
more->match = 0;
|
|
Packit |
992a25 |
more->row = 1;
|
|
Packit |
992a25 |
more->col = 1;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
return 0;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/*
|
|
Packit |
992a25 |
* push the more discipline on f
|
|
Packit |
992a25 |
* if prompt==0 then a default ansi prompt is used
|
|
Packit |
992a25 |
* if rows==0 or cols==0 then they are deterimined from the tty
|
|
Packit |
992a25 |
* if f==sfstdout then input on sfstdin also resets the state
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#if __STD_C
|
|
Packit |
992a25 |
int sfdcmore(Sfio_t* f, const char* prompt, int rows, int cols)
|
|
Packit |
992a25 |
#else
|
|
Packit |
992a25 |
int sfdcmore(f, prompt, rows, cols)
|
|
Packit |
992a25 |
Sfio_t* f;
|
|
Packit |
992a25 |
char* prompt;
|
|
Packit |
992a25 |
int rows;
|
|
Packit |
992a25 |
int cols;
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
register More_t* more;
|
|
Packit |
992a25 |
size_t n;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/*
|
|
Packit |
992a25 |
* this is a writeonly discipline for interactive io
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if (!(sfset(f, 0, 0) & SF_WRITE) || !isatty(sffileno(sfstdin)) || !isatty(sffileno(sfstdout)))
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
if (!prompt)
|
|
Packit |
992a25 |
prompt = "\033[7m More\033[m";
|
|
Packit |
992a25 |
n = strlen(prompt) + 1;
|
|
Packit |
992a25 |
if (!(more = (More_t*)malloc(sizeof(More_t) + n)))
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
memset(more, 0, sizeof(*more));
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
more->disc.readf = moreread;
|
|
Packit |
992a25 |
more->disc.writef = morewrite;
|
|
Packit |
992a25 |
more->disc.exceptf = moreexcept;
|
|
Packit |
992a25 |
memcpy(more->prompt, prompt, n);
|
|
Packit |
992a25 |
if (!rows || !cols)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
#if _PACKAGE_ast
|
|
Packit |
992a25 |
astwinsize(sffileno(sfstdin), &rows, &cols;;
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
if (!rows)
|
|
Packit |
992a25 |
rows = 24;
|
|
Packit |
992a25 |
if (!cols)
|
|
Packit |
992a25 |
cols = 80;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
more->rows = rows;
|
|
Packit |
992a25 |
more->cols = cols;
|
|
Packit |
992a25 |
more->row = 1;
|
|
Packit |
992a25 |
more->col = 1;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if (sfdisc(f, &more->disc) != &more->disc)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
free(more);
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
if (f == sfstdout)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
if (sfdisc(sfstdin, &more->disc) != &more->disc)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
sfdisc(f, SF_POPDISC);
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
more->input = sfstdin;
|
|
Packit |
992a25 |
if (sfdisc(sfstderr, &more->disc) != &more->disc)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
sfdisc(f, SF_POPDISC);
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
more->error = sfstdin;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
return 0;
|
|
Packit |
992a25 |
}
|