NetBSD/usr.bin/msgc/msg_sys.def
dsl ee1a61d7eb No need for wrefresh() in msg_clear(), screen will be updated later.
Stops obvious redraw of header of some menus.
2003-07-28 09:55:24 +00:00

498 lines
11 KiB
Modula-2

/* $NetBSD: msg_sys.def,v 1.25 2003/07/28 09:55:24 dsl Exp $ */
/*
* Copyright 1997 Piermont Information Systems Inc.
* All rights reserved.
*
* Written by Philip A. Nelson for Piermont Information Systems Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software develooped for the NetBSD Project by
* Piermont Information Systems Inc.
* 4. The name of Piermont Information Systems Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
*/
static WINDOW *msg_win = NULL;
static char *cbuffer;
static size_t cbuffersize;
static int last_i_was_nl, last_i_was_space;
static int last_o_was_punct, last_o_was_space;
static void _msg_beep(void);
static int _msg_vprintf(int, const char *, va_list);
static void _msg_vprompt(const char *, int, const char *, char *,
size_t, va_list);
static char *msgmap = MAP_FAILED;
static size_t msgmapsz;
static int msgmapcount;
/* Routines */
static void
_msg_beep(void)
{
fprintf(stderr, "\a");
}
WINDOW *
msg_window(WINDOW *window)
{
size_t ncbuffersize;
char *ncbuffer;
WINDOW *old;
old = msg_win;
if (!window)
return old;
msg_win = window;
ncbuffersize = getmaxx(window) * getmaxy(window) + 1;
while (ncbuffersize > cbuffersize) {
ncbuffer = malloc(ncbuffersize);
if (ncbuffer == NULL) {
/* we might get truncated messages... */
ncbuffersize <<= 1;
continue;
}
if (cbuffer != NULL)
free(cbuffer);
cbuffer = ncbuffer;
cbuffersize = ncbuffersize;
break;
}
last_o_was_punct = 0;
last_o_was_space = 1;
return old;
}
int
msg_file(const char *file)
{
int fd;
if (msgmap != MAP_FAILED)
munmap(msgmap, msgmapsz);
msgmap = MAP_FAILED;
if (!file)
return 0;
fd = open(file, O_RDONLY, 0);
if (fd == -1)
return -1;
msgmapsz = lseek(fd, 0, SEEK_END);
msgmap = mmap(0, msgmapsz, PROT_READ, MAP_SHARED, fd, 0);
close(fd);
if (msgmap == MAP_FAILED)
return -1;
/* check_magic */
if (strcmp(msgmap, "MSGTXTS") != 0) {
msg_file(NULL);
return -1;
}
msgmapcount = atoi(msgmap + 8);
return 0;
}
const char *
msg_string(msg msg_no)
{
int m = (intptr_t)msg_no;
if (m > sizeof msg_list / sizeof msg_list[0])
/* guess that we were passed a text string */
return msg_no;
if (msgmap != MAP_FAILED && m != 0 && m <= msgmapcount) {
unsigned int offset = atoi(msgmap + 8 + 8 * m);
if (offset != 0 && offset < msgmapsz)
return msgmap + offset;
}
return msg_list[m];
}
void
msg_clear(void)
{
wclear(msg_win);
last_o_was_punct = 0;
last_o_was_space = 1;
}
void
msg_standout(void)
{
wstandout(msg_win);
}
void
msg_standend(void)
{
wstandend(msg_win);
}
static int
_msg_vprintf(int auto_fill, const char *fmt, va_list ap)
{
const char *wstart, *afterw;
int wordlen, nspaces;
int ret;
ret = vsnprintf(cbuffer, cbuffersize, fmt, ap);
if (!auto_fill) {
waddstr(msg_win, cbuffer);
/*
* nothing is perfect if they flow text after a table,
* but this may be decent.
*/
last_i_was_nl = last_i_was_space = 1;
last_o_was_punct = 0;
last_o_was_space = 1;
goto out;
}
for (wstart = afterw = cbuffer; *wstart; wstart = afterw) {
/* eat one space, or a whole word of non-spaces */
if (isspace(*afterw))
afterw++;
else
while (*afterw && !isspace(*afterw))
afterw++;
/* this is an nl: special formatting necessary */
if (*wstart == '\n') {
if (last_i_was_nl || last_i_was_space) {
if (getcurx(msg_win) != 0)
waddch(msg_win, '\n');
if (last_i_was_nl) {
/* last was an nl: paragraph break */
waddch(msg_win, '\n');
} else {
/* last was space: line break */
}
last_o_was_punct = 0;
last_o_was_space = 1;
} else {
/* last_o_was_punct unchanged */
/* last_o_was_space unchanged */
}
last_i_was_space = 1;
last_i_was_nl = 1;
continue;
}
/* this is a tab: special formatting necessary. */
if (*wstart == '\t') {
if (last_i_was_nl) {
/* last was an nl: list indent */
if (getcurx(msg_win) != 0)
waddch(msg_win, '\n');
} else {
/* last was not an nl: columns */
}
waddch(msg_win, '\t');
last_i_was_nl = 0;
last_i_was_space = 1;
last_o_was_punct = 0;
last_o_was_space = 1;
continue;
}
/* this is a space: ignore it but set flags */
last_i_was_nl = 0; /* all newlines handled above */
last_i_was_space = isspace(*wstart);
if (last_i_was_space)
continue;
/*
* we have a real "word," i.e. a sequence of non-space
* characters. wstart is now the start of the word,
* afterw is the next character after the end.
*/
wordlen = afterw - wstart;
nspaces = last_o_was_space ? 0 : (last_o_was_punct ? 2 : 1);
if ((getcurx(msg_win) + nspaces + wordlen) >=
getmaxx(msg_win) &&
wordlen < (getmaxx(msg_win) / 3)) {
/* wrap the line */
waddch(msg_win, '\n');
nspaces = 0;
}
/* output the word, preceded by spaces if necessary */
while (nspaces-- > 0)
waddch(msg_win, ' ');
waddbytes(msg_win, wstart, wordlen);
/* set up the 'last' state for the next time around */
switch (afterw[-1]) {
case '.':
case '?':
case '!':
last_o_was_punct = 1;
break;
default:
last_o_was_punct = 0;
break;
}
last_o_was_space = 0;
/* ... and do it all again! */
}
/* String ended with a newline. They really want a line break. */
if (last_i_was_nl) {
if (getcurx(msg_win) != 0)
waddch(msg_win, '\n');
last_o_was_punct = 0;
last_o_was_space = 1;
}
out:
wrefresh(msg_win);
return ret;
}
void
msg_display(msg msg_no, ...)
{
va_list ap;
msg_clear();
va_start(ap, msg_no);
(void)_msg_vprintf(1, msg_string(msg_no), ap);
va_end(ap);
}
void
msg_display_add(msg msg_no, ...)
{
va_list ap;
va_start(ap, msg_no);
(void)_msg_vprintf(1, msg_string(msg_no), ap);
va_end(ap);
}
static void
_erase_ch(void)
{
int y, x;
getyx(msg_win, y, x);
x--;
wmove(msg_win, y, x);
waddch(msg_win, ' ');
wmove(msg_win, y, x);
}
static void
_msg_vprompt(const char *fmt, int do_echo, const char *def, char *val,
size_t max_chars, va_list ap)
{
int ch;
int count = 0;
char *ibuf = alloca(max_chars);
_msg_vprintf(0, fmt, ap);
if (def != NULL && *def) {
waddstr(msg_win, " [");
waddstr(msg_win, def);
waddstr(msg_win, "]");
}
waddstr(msg_win, ": ");
wrefresh(msg_win);
while ((ch = wgetch(msg_win)) != '\n') {
if (ch == 0x08 || ch == 0x7f) { /* bs or del */
if (count > 0) {
count--;
if (do_echo)
_erase_ch();
} else
_msg_beep();
} else if (ch == 0x15) { /* ^U; line kill */
while (count > 0) {
count--;
if (do_echo)
_erase_ch();
}
} else if (ch == 0x17) { /* ^W; word kill */
/*
* word kill kills the spaces and the 'word'
* (non-spaces) last typed. the spaces before
* the 'word' aren't killed.
*/
while (count > 0 && isspace(ibuf[count - 1])) {
count--;
if (do_echo)
_erase_ch();
}
while (count > 0 && !isspace(ibuf[count - 1])) {
count--;
if (do_echo)
_erase_ch();
}
} else if (count < (max_chars - 1) && isprint(ch)) {
if (do_echo)
waddch(msg_win, ch);
ibuf[count++] = ch;
} else
_msg_beep();
if (do_echo)
wrefresh(msg_win);
}
if (do_echo) {
waddch(msg_win, '\n');
last_o_was_punct = 0;
last_o_was_space = 1;
}
/* copy the appropriate string to the output */
if (count != 0) {
ibuf[count] = '\0';
strlcpy(val, ibuf, max_chars);
} else if (def != NULL && val != def) {
strlcpy(val, def, max_chars);
}
}
void
msg_prompt(msg msg_no, const char *def, char *val, size_t max_chars, ...)
{
va_list ap;
msg_clear();
va_start(ap, max_chars);
_msg_vprompt(msg_string(msg_no), 1, def, val, max_chars, ap);
va_end(ap);
}
void
msg_prompt_win(msg msg_no, int x, int y, int w, int h,
const char *def, char *val, size_t max_chars, ...)
{
va_list ap;
WINDOW *win, *svwin;
int maxx, maxy;
maxx = getmaxx(msg_win);
maxy = getmaxy(msg_win);
if (w == 0) {
va_start(ap, max_chars);
w = vsnprintf(NULL, 0, msg_string(msg_no), ap);
va_end(ap);
if (def != NULL && *def != 0)
w += 2 + strlen(def) + 1;
w += 1 + 2 + max_chars + 1;
if (w > maxx)
w = maxx;
}
if (x == -1)
x = (maxx - w) / 2;
if (h < 3)
h = 3;
if (y < 3)
y = (maxy - h) / 2;
if (y + h > maxy)
y = maxy - h;
win = subwin(msg_win, h, w, y, x);
if (win == NULL)
wprintw(msg_win, "msg_prompt_win: "
"newwin(%d, %d, %d, %d) failed\n",
h, w, y, x);
else {
wbkgd(win, getbkgd(msg_win));
wattrset(win, getattrs(msg_win));
box(win, 0, 0);
wrefresh(win);
svwin = msg_window(subwin(msg_win, h - 2, w - 2, y + 1, x + 1));
wbkgd(msg_win, getbkgd(win));
wattrset(msg_win, getattrs(win));
msg_clear();
}
va_start(ap, max_chars);
_msg_vprompt(msg_string(msg_no), 1, def, val, max_chars, ap);
va_end(ap);
if (win != NULL) {
wclear(win);
wrefresh(win);
delwin(msg_window(svwin));
delwin(win);
}
}
void
msg_prompt_add(msg msg_no, const char *def, char *val, size_t max_chars, ...)
{
va_list ap;
va_start(ap, max_chars);
_msg_vprompt(msg_string(msg_no), 1, def, val, max_chars, ap);
va_end(ap);
}
void
msg_prompt_noecho(msg msg_no, const char *def, char *val, size_t max_chars, ...)
{
va_list ap;
msg_clear();
va_start(ap, max_chars);
_msg_vprompt(msg_string(msg_no), 0, def, val, max_chars, ap);
va_end(ap);
}
void
msg_table_add(msg msg_no, ...)
{
va_list ap;
va_start(ap, msg_no);
(void)_msg_vprintf(0, msg_string(msg_no), ap);
va_end(ap);
}