static char rcsid[] = "@(#)$Id: builtin++.c,v 1.30 2006/04/09 07:37:17 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.30 $ $State: Exp $
*
* Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* (was hurtta+elm@ozone.FMI.FI)
*
* Initially written by: Michael Elkins <elkins@aero.org>, 1995
*****************************************************************************/
#include "def_elm.h"
#include "s_elm.h"
DEBUG_VAR(Debug,__FILE__,"ui");
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
extern int tabspacing;
static void builtin_help P_((void));
static void builtin_help ()
{
/* A help screen for the pager below. */
int LINES, COLUMNS;
struct menu_context *page = new_menu_context();
redraw:
if (menu_resized(page) ||
menu_need_redraw(page))
/* Nothing */;
menu_get_sizes(page, &LINES, &COLUMNS);
menu_ClearScreen(page);
StartInverse();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpTitle,
"Help for builtin++"));
EndInverse();
NewLine ();
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpKeyA,
"Key\t\tAction"));
NewLine ();
Write_to_screen (FRM("---\t\t------"));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpSpace,
"<SPACE>, +\tNext page."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpMinus,
"-\t\tPrevious page."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpReturn,
"<RETURN>\tNext line."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpq,
"q, x, i\t\tReturn to the index menu."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpDiv,
"/\t\tSearch for pattern in message."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpArr,
"^\t\tFirst page."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpG,
"G\t\tLast page."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpCtrlL,
"^L\t\tRefresh display."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpCtrlP,
"^P\t\tUp one line."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpCtrlP,
"^D\t\tDown one-half page."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpCtrlU,
"^U\t\tUp one-half page."));
NewLine ();
Write_to_screen (CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpQuestion,
"?\t\tThis help screen."));
NewLine ();
menu_PutLineX (page,
LINES-1, 0,
CATGETS(elm_msg_cat, ElmSet, ElmBuiltinHelpPressRet,
"Press any key to return..."));
if (REDRAW_MARK == menu_ReadCh(page,REDRAW_MARK))
goto redraw;
erase_menu_context(&page);
return;
}
static int search_it P_((struct stringbuffer * bout, int start_idx,
struct string * search_pattern));
static int search_it(bout,start_idx,search_pattern)
struct stringbuffer * bout;
int start_idx;
struct string * search_pattern;
{
int ret = 0;
int idx = start_idx;
while (idx < linecount_stringbuffer(bout) && !ret) {
struct string * buffer = get_line_from_stringbuffer(bout,idx);
if (find_pattern_from_string(buffer,search_pattern,1))
ret = idx;
idx++;
free_string(&buffer);
}
DPRINT(Debug,3,
(&Debug,"Builtin pager: Search from line %d %s (%d)\n",
start_idx,
ret ? "SUCCEED" : "FAILED",
ret));
return ret;
}
int builtinplusplus (bout,pager_page)
struct stringbuffer * bout;
struct pager_page * pager_page;
{
int idx = 0;
int is_end = 0;
/* Current line for outputting and position on it ... */
struct string * buffer = NULL;
int ret = '\0';
int X = 0;
struct string * search_pattern = NULL; /* Last seach string */
clear_error();
for (;;) {
int idx_top; /* line number of top of display */
int ch; /* command key read */
int search_matches = 0; /* First idx on page where search matches */
int lines; /* Number of visible lines printed
so far */
int FF_seen; /* If page is breaken because of FF */
int LINES, COLUMNS;
new_page:
resize_mark:
idx_top = idx; /* line number of top of display */
lines = 0; /* Number of visible lines printed
so far */
FF_seen = 0;
menu_ClearScreen(pager_page->root);
cr_restart: /* so that we can handle CR specially --
ie. don't reset page variables
*/
menu_get_sizes(pager_page->root, &LINES, &COLUMNS);
DPRINT(Debug,5,(&Debug, "builtin++ top idx = %d\n",idx));
while ((idx < linecount_stringbuffer(bout)) &&
lines < LINES-1 && !FF_seen) {
int chars = 0; /* Number of characters on current line */
int mayclear = 1;
int buffer_len = -1;
int visible_len;
if (menu_resized(pager_page->root)) {
menu_get_sizes(pager_page->root, &LINES, &COLUMNS);
if (buffer)
free_string(&buffer);
idx= idx_top;
goto new_page;
}
if (menu_need_redraw(pager_page->root)) {
if (buffer)
free_string(&buffer);
idx= idx_top;
goto new_page;
}
DPRINT(Debug,9,(&Debug,
"builtin++ before line idx = %d X=%d\n",
idx,X));
if (!buffer || X >= (buffer_len = string_len(buffer))) {
/* caller of get_line_from_stringbuffer is expected to
free_string () resulting buffer */
if (buffer) {
if (X >= buffer_len)
idx++;
if (idx >= linecount_stringbuffer(bout))
break;
free_string (&buffer);
}
X = 0;
/* There is no pending data to output, so we need to grab
* another line.
*/
buffer = get_line_from_stringbuffer(bout,idx);
buffer_len = string_len(buffer);
}
/* This is the part of the code that actually displays on
* the screen
*/
chars = 0;
while (X < buffer_len) {
uint16 ch;
int len = 0; /* Length for next clip ... */
struct string * data;
/* If no space for next character */
if (chars >= COLUMNS)
break;
ch = give_unicode_from_string(buffer,X);
if (ch <= 31) {
/* Make sure that carbage from previous
output is not left */
if (mayclear) {
CleartoEOLN();
mayclear = 0;
}
switch(ch) {
case 0x0009: /* HT */
Writechar('\t');
chars = ((chars / get_tabspacing() ) +1) *
get_tabspacing();
break;
case 0x000C: /* FF */
case 0x000B: /* VT */
FF_seen = 1;
/* FALLTHRU */
case 0x000A: /* LF */
X++;
goto out;
default:
/* This won't fit on the line, so just skip it
for now */
if (chars == COLUMNS - 1)
break;
/* Output character set is assumed to be ASCII
compatible on here: */
StartBold();
Writechar('^');
Writechar(ch + 64);
EndBold();
chars += 2;
break;
}
X++;
continue;
}
DPRINT(Debug,9,(&Debug,
"builtin++ after ctrl X=%d (chars = %d)\n",
X,chars));
/* calculate clip len ... */
while (X + len < buffer_len &&
chars + len < COLUMNS) {
ch = give_unicode_from_string(buffer,X+len);
if (ch <= 31)
break;
len++;
}
DPRINT(Debug,9,(&Debug,
"builtin++ after text X=%d ( len = %d)\n",
X,len));
if (len < 1)
continue; /* next character was also control char */
/* clip_from_string updates X */
data = curses_printable_clip(buffer,&X,len,&visible_len,
COLUMNS - chars);
if (data) {
chars += visible_len;
DPRINT(Debug,9,(&Debug,
"builtin++ after clip idx = %d X=%d (len = %d, chars=%d visible_len=%d)\n",
idx,X,len,chars, visible_len));
if (search_matches &&
search_matches == idx)
StartBold();
Write_to_screen(FRM("%S"),data);
if (search_matches &&
search_matches == idx)
EndBold();
free_string(&data);
if (visible_len < 1) {
DPRINT(Debug,9,(&Debug,
"builtin++ --- No space for next character on line\n"));
goto out;
}
} else {
/* Treat next character as control character */
/* Output character set is assumed to be ASCII
compatible on here: */
StartBold();
Writechar('?');
EndBold();
chars += 1;
X++;
}
}
/* Make sure that carbage from previous
output is not left */
if (mayclear) {
CleartoEOLN();
mayclear = 0;
}
out:
NewLine();
lines++;
}
CleartoEOS();
if (lines < LINES-1 && FF_seen) {
StartBold();
PutLineX (lines, 0,
CATGETS(elm_msg_cat, ElmSet, ElmBuiltinNewPage,
"~ (new page) "));
EndBold(); CleartoEOLN();
NewLine();
lines++;
}
while (lines < LINES-1) {
Writechar('~'); NewLine();
CleartoEOLN();
lines++;
}
reprompt:
StartBold();
if (idx >= linecount_stringbuffer(bout)) {
menu_PutLineX (pager_page->root,LINES-1, 0,
CATGETS(elm_msg_cat, ElmSet, ElmBuiltinCommandi,
"Command ('i' to return to index):"));
is_end = 1;
}
else {
int relative;
int ul = give_dt_enumerate_as_int(&user_level);
if (linecount_stringbuffer(bout) < 1)
relative = 100;
else
relative = 100 * idx / linecount_stringbuffer(bout);
if (ul == 0)
menu_PutLineX(pager_page->root,LINES-1, 0,
CATGETS(elm_msg_cat, ElmSet, ElmBuiltInMore0,
"MORE (line %d-%d/%d, you've seen %d%%). Press <space> for more:"),
idx_top+1,idx,linecount_stringbuffer(bout),
relative);
else
menu_PutLineX(pager_page->root,
LINES-1, 0,
CATGETS(elm_msg_cat, ElmSet, ElmBuiltInMore,
"MORE (line %d-%d/%d, you've seen %d%%):"),
idx_top+1,idx,linecount_stringbuffer(bout),
relative);
is_end = 0;
}
EndBold();
CleartoEOS();
read_key:
ch = menu_ReadCh(pager_page->root, REDRAW_MARK|READCH_CURSOR|READCH_resize|
READCH_sig_char);
if (ch != '/') {
if (search_pattern) {
free_string(&search_pattern);
}
}
switch (ch) {
case TERMCH_interrupt_char:
ret = 0;
goto finish;
case RESIZE_MARK:
DPRINT(Debug,4, (&Debug, " ... resizing\n"));
idx = idx_top;
goto resize_mark;
case ' ':
case '+':
case PAGEDOWN_MARK:
if (is_end) {
ret = ' ';
goto finish;
}
break;
case HOME_MARK:
case '^':
idx = 0;
/* Avoid incrementing of idx: */
if (buffer)
free_string (&buffer);
break;
case 'G':
/* Not completely correct if multiline lines */
idx = linecount_stringbuffer(bout)-LINES;
if (idx < 0)
idx = 0;
lines = 0;
/* Avoid incrementing of idx: */
if (buffer)
free_string (&buffer);
menu_ClearScreen(pager_page->root);
break;
case FIND_MARK:
case '/':
ClearLine (LINES-1);
{
int code;
code = optionally_enter2(pager_page->root,
&search_pattern,
LINES-1, 0,
OE_REDRAW_MARK|
OE_SIG_CHAR /* Ctrl-C */,
CATGETS(elm_msg_cat, ElmSet,
ElmBuiltinSearch,
"Search: "));
if (REDRAW_MARK == code)
goto redraw;
if (-1 == code) /* Ctrl-C */
goto reprompt;
if (code != 0)
goto quit;
if (search_pattern && string_len(search_pattern)) {
int start_idx;
/* Continue search from previous match */
if (!search_matches)
start_idx = idx_top;
else if (search_matches < linecount_stringbuffer(bout))
start_idx = search_matches+1;
else
start_idx = idx_top;
search_matches = search_it(bout,start_idx,
search_pattern);
if (search_matches) {
if (search_matches > idx_top &&
search_matches < idx_top + LINES -4)
idx = idx_top;
else
idx = search_matches - LINES / 2;
if (idx < 0)
idx = 0;
/* Avoid incrementing of idx: */
if (buffer)
free_string (&buffer);
goto new_page; /* and draw match */
} else {
int relative;
int ul = give_dt_enumerate_as_int(&user_level);
if (linecount_stringbuffer(bout) < 1)
relative = 100;
else
relative = 100 * idx / linecount_stringbuffer(bout);
ClearLine (LINES-1);
StartBold();
if (ul == 0)
PutLineX (LINES-1, 0,
CATGETS(elm_msg_cat, ElmSet, ElmBuiltInNotFound0,
"NOT FOUND! (line %d-%d/%d, you've seen %d%%). Press <space> for more:"),
idx_top+1,idx,linecount_stringbuffer(bout),
relative);
else
PutLineX (LINES-1, 0,
CATGETS(elm_msg_cat, ElmSet,
ElmBuiltInNotFound,
"NOT FOUND! (line %d-%d/%d, you've seen %d%%):"),
idx_top+1,idx,linecount_stringbuffer(bout),
relative);
EndBold();
goto read_key;
}
}
goto reprompt;
}
case PAGEUP_MARK:
case '-':
idx = idx_top - LINES;
if (idx < 0)
idx = 0;
if (buffer)
free_string(&buffer);
break;
case ctrl('P'):
idx = idx_top -1;
if (idx < 0)
idx = 0;
if (buffer)
free_string(&buffer);
break;
case ctrl('D'):
if (is_end)
goto reprompt; /* Can't go down */
lines = LINES / 2;
CarriageReturn();
CleartoEOLN();
idx_top += LINES / 2;
goto cr_restart; /* Hanlde Ctrl-D specially */
case ctrl('U'):
idx = idx_top - LINES / 2;
if (idx < 0)
idx = 0;
if (buffer)
free_string(&buffer);
break;
case HELP_MARK:
case '?':
builtin_help ();
/* FALLTHRU */
redraw:
case REDRAW_MARK:
case ctrl('L'):
idx = idx_top;
if (buffer)
free_string(&buffer);
break;
case '\n':
if (FF_seen)
break; /* New page */
{
int x, y;
GetXYLocation (&x, &y);
ClearLine (x);
}
lines = LINES - 2;
idx_top++;
goto cr_restart; /* Hanlde CR specially */
quit:
case EOF:
default:
ret = (ch == 'q' || ch == 'x' ? 0 : ch);
goto finish;
}
}
finish:
if (buffer)
free_string (&buffer);
DPRINT(Debug,9,(&Debug,
"builtin++ returning %c\n",ret));
return ret;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1