/********************************************************************
* $Author: jgoerzen $
* $Revision: 1.5 $
* $Date: 2002/01/08 17:36:14 $
* $Source: /home/jgoerzen/tmp/gopher-umn/gopher/head/gopher/CURcurses.c,v $
* $State: Exp $
*
* Paul Lindner, University of Minnesota CIS.
*
* Copyright 1991, 1992 by the Regents of the University of Minnesota
* see the file "Copyright" in the distribution for conditions of use.
*********************************************************************
* MODULE: CURcurses.c
* Abstraction of all Curses Functions
*********************************************************************
* Revision History:
* $Log: CURcurses.c,v $
* Revision 1.5 2002/01/08 17:36:14 jgoerzen
* Finally builds!
*
* Changes:
*
* * config.h.in: rebuilt by autoheader
*
* * configure: rebuilt by autoconf
*
* * configure.in:
* * Added REGEXLIBS test for NetBSD -- look for re_comp in -lcompat
* * Added checkes for term.h, re_comp.h, regex.h
*
* * gopher/ourutils.c, gopher/CURcurses.c: Use term.h check
*
* * gopher/Makefile.in, gopherd/Makefile.in, gophfilt/Makefile.in:
* * Use REGEXLIBS
*
* * gopher/globals.h, gopher/gopher.c: Remove sys_errlist
*
* * object/GSgopherobj.c: Removed <regex.h> #include, now use
* "Regex.h" that has proper regex determining logic
*
* * object/Regex.h: Moved regex.h include to here. Make it conditional
* based on configure test. Add conditional re_comp.h include.
*
* Revision 1.4 2001/01/17 21:48:05 jgoerzen
* Many fixes and tune-ups. Now compiles cleanly with -Wall -Werror!
*
* Revision 1.3 2001/01/03 22:25:57 s2mdalle
* Code cleanups, fixes for copious compiler warnings.
*
* Revision 1.2 2000/12/27 21:25:01 s2mdalle
* Added #include "gopher.h"
*
* Revision 1.1.1.1 2000/08/19 00:28:56 jgoerzen
* Import from UMN Gopher 2.3.1 after GPLization
*
* Revision 3.61 1996/01/04 18:28:51 lindner
* Updates for autoconf
*
* Revision 3.60 1995/11/03 21:18:15 lindner
* ANSIfication
*
* Revision 3.59 1995/11/03 20:50:47 lindner
* Coen: fixes..
*
* Revision 3.58 1995/05/02 06:06:57 lindner
* Fix for message str..
*
* Revision 3.57 1995/04/15 07:09:46 lindner
* New funky C-x stuff
*
* Revision 3.56 1995/03/09 05:24:39 lindner
* F.Macrides 01-Mar-1995 Removed the CURsetScreen(cur, initscr()) that
* someone #ifdef'ed for VMS in CURresize().
*
* Revision 3.55 1995/02/27 17:44:51 lindner
* New pacbell fcn CURrightline
*
* Revision 3.54 1995/02/07 19:34:41 lindner
* Fix for unix systems without SIGTSTP
*
* Revision 3.53 1995/01/25 23:09:24 lindner
* Word wrapping in gopher forms, provided by Pacific Bell Knowledge Net
*
* Revision 3.52 1994/12/03 01:51:39 lindner
* Fix prototype for DCLspawn_exception
*
* Revision 3.51 1994/10/21 04:41:07 lindner
* Add ANSI attached printer code..
*
* Revision 3.50 1994/06/29 07:06:59 lindner
* moved gcatd to Locale.[ch] (Coopersmith)
*
* Revision 3.49 1994/06/29 05:11:07 lindner
* None..
*
* Revision 3.48 1994/06/12 05:28:17 lindner
* Fix for locales
*
* Revision 3.47 1994/06/09 22:13:35 lindner
* More language conversions
*
* Revision 3.46 1994/05/24 05:49:54 lindner
* Fix for bad free() in CURrequest()
*
* Revision 3.45 1994/04/25 20:43:29 lindner
* Remove ugly pointer debug statement
*
* Revision 3.44 1994/04/25 03:49:41 lindner
* Fixed ^_ mislabel of the ^- help command.
*
* Added prompt for RETURN in VMSExit(), to enable reading of ACCVIO tracebacks.
*
* Changed return values of DCLSystem() to be compatible with the
* for-Unix code.
*
* Fixed spawns to work with OpenVMS/AXP v6.1 (still doesn't have the
* TRUSTED flag).
*
* Revision 3.43 1994/04/25 03:37:35 lindner
* Modifications for Debug() and mismatched NULL arguments, added Debugmsg
*
* Revision 3.42 1994/04/13 19:13:20 lindner
* AskL modifications
*
* Revision 3.41 1994/04/01 02:24:41 lindner
* Remove debugging stuff
*
* Revision 3.40 1994/03/31 21:26:43 lindner
* Mitra's debug routine
*
* Revision 3.39 1994/03/08 15:55:02 lindner
* gcc -Wall fixes
*
* Revision 3.38 1994/03/04 23:39:45 lindner
* Fix for log entries
*
* Revision 3.37 1994/03/04 23:36:28 lindner
* Many, many fixes and enhancements for Beckett and Co.
*
* Revision 3.36 1994/02/21 15:47:34 lindner
* Remove conditional compilation for DEC ALPHAS trusted flag on VMS
*
* Revision 3.35 1994/02/20 21:45:18 lindner
* Better sanity checks for box drawing characters
*
* Revision 3.34 1994/01/20 06:46:15 lindner
* Fix boundary condition
*
* Revision 3.33 1994/01/14 16:40:04 lindner
* Added VMSVersion() for getting the VMS version number, and modified
* spawn_DCLprocess() so that it includes the TRUSTED flag for VAX v6+
* and AXP v2+. If DEC changes AXP v2.0 to v6.1 (I've heard rumors to
* that affect), remove the __ALPHA conditional compilation in
* spawn_DCLprocess() so it just checks for v6+.
*
* Revision 3.32 1993/12/28 17:29:09 lindner
* Better method of drawing box characters
*
* Revision 3.31 1993/11/04 02:06:50 lindner
* Add Ben's AIS hack
*
* Revision 3.30 1993/10/26 18:24:31 lindner
* Make sure we cleanup before exiting
*
* Revision 3.29 1993/10/26 18:12:56 lindner
* Fixes for Input routines, screen redrawing, ASK fixes
*
* Revision 3.28 1993/10/22 20:22:12 lindner
* Range checks for lots of things
*
* Revision 3.27 1993/10/07 05:10:12 lindner
* Make TrimmedTitle[] (twice) a larger array (256 elements). Makes
* 132-column terminals and huge xterm windows happier.
*
* In CURwgetch(), fix vt100 "Help" escape sequence. Add vt100 "Enter",
* vt200 "Help", and vt200 "Do" escape sequences.
*
* Revision 3.26 1993/09/30 22:41:57 lindner
* Add option for bolding of searched words
*
* Revision 3.25 1993/09/29 22:47:17 lindner
* Fix for AskBlock memory cruft
*
* Revision 3.24 1993/09/29 20:52:47 lindner
* Add [space to cycle] prompt earlier
*
* Revision 3.23 1993/09/26 09:19:19 lindner
* Add bold #defines
*
* Revision 3.22 1993/09/22 19:58:15 lindner
* Fix for extra cruft on screen from Select/Choose
*
* Revision 3.21 1993/09/22 04:13:44 lindner
* none
*
* Revision 3.20 1993/09/22 01:15:44 lindner
* Add support for DEC HELP key/KEY_HELP
*
* Revision 3.19 1993/09/21 02:42:18 lindner
* Exit on error reading from terminal (kills spinning processes)
*
* Revision 3.18 1993/09/21 01:46:06 lindner
* Implement all remaining ASK block items..
*
* Revision 3.17 1993/09/11 06:31:33 lindner
* spelling correction
*
* Revision 3.16 1993/09/11 04:51:00 lindner
* Fix to skip labels in CURrequest()
*
* Revision 3.15 1993/09/03 03:28:59 lindner
* Modified CURGetOneOption() to have a Title field. Serveral other
* routines modified for improved line editing and to show all available
* commands while answering prompts. If dialog box has only one prompt,
* as for search query entries, start user entry on new line so more of
* the screen is available for the entry (useful for search terms with
* booleans).
*
* Revision 3.14 1993/08/19 20:22:45 lindner
* Mitra's Debug patch
*
* Revision 3.13 1993/08/16 18:17:01 lindner
* Fixes from F.Macrides:
*
* Added temporary code to work around DECC/AXP's problems with screen
* clearing and cursor homing (we'll get rid of that code if the problem
* goes away in the next version of DECC/AXP). It's bolding via
* standout() or wstandout(win) still doesn't work, but that's not a
* serious functional problem for gopher users on Alphas.
*
* Added exit block to ensure that the terminal characteristics are
* retored and cleanups are done on VMS.
*
* Added code for getting terminal characteristics
* from the terminal table on VMS.
*
* Replaced/modified Cruft for VMS with routines which handle both
* Control C and Control Y, enable use of ReallyQuit(), and restore all
* original terminal characteristics for spawns and intentional or
* unintentional exits. Did it in a way that should stay transparent to
* the otherwise "for-Unix" code, and should hold up with future mods or
* enhancements of that code. Standout() doesn't work at all and
* endwin() and delwin() are unreliable on Alphas (due to bugs in the
* Alpha's Curses library). Andrew Heyler is looking into workarounds,
* should DEC not fix the bugs soon. Code compiles with DECC on Alphas
* without warnings or error messages, but still get lots of
* "informational" messages due to incomplete prototyping (no problems or
* compiler messages with VAXC).
*
* Revision 3.12 1993/08/12 06:32:06 lindner
* Add needed variable
*
* Revision 3.11 1993/08/09 20:44:48 lindner
* Fix for really long strings
*
* Revision 3.10 1993/08/09 20:29:50 lindner
* Get rid of the beep during a ^G in CURwgetstr().
*
* Make CURChoice() delete its window when it exits.
*
* Revision 3.9 1993/07/30 17:31:34 lindner
* Mods to support AskP:
*
* Revision 3.8 1993/07/27 02:02:47 lindner
* More comments
*
* Revision 3.7 1993/07/23 04:33:48 lindner
* Mods to curchoice for default
*
* Revision 3.6 1993/07/20 23:10:17 lindner
* none
*
* Revision 3.5 1993/04/15 21:23:36 lindner
* Removed extraneous wattron/wattroff
*
* Revision 3.4 1993/03/26 19:42:32 lindner
* Fix for skip by two problem in CURrequest
*
* Revision 3.3 1993/03/18 23:15:24 lindner
* Mods to support titles inside of a CURrequest.
*
* Revision 3.2 1993/02/16 23:26:02 lindner
* Fixes for SIG_ERR (for Crays)
*
* Revision 3.1.1.1 1993/02/11 18:02:56 lindner
* Gopher+1.2beta release
*
* Revision 1.8 1993/01/11 20:25:31 lindner
* Fixed weird wprintw error on EP/IX.
*
* Revision 1.8 1993/01/11 20:25:31 lindner
* Fixed weird wprintw error on EP/IX.
*
* Revision 1.7 1993/01/09 02:16:21 lindner
* Changed (void*)-1 constructs to SIG_ERR
*
* Revision 1.6 1993/01/09 01:28:11 lindner
* Replaced hosed Log messages (Ooops!)
*
* Revision 1.5 1993/01/09 01:24:42 lindner
* Added CURchoice(), let's you choose one option from [2-9] items.
*
* Revision 1.4 1993/01/09 00:49:16 lindner
* More mods for VMS from jqj. Looks like better ctrl-y and ctrl-c
* processing.
*
* Revision 1.3 1993/01/06 17:05:46 lindner
* Added nl() to CURexit() for EP/IX machines.
*
* Revision 1.2 1992/12/31 05:55:44 lindner
* Mods for VMS
*
* Revision 1.1 1992/12/10 06:16:51 lindner
* Initial revision
*
*
*********************************************************************/
#if defined(A_ALTCHARSET) && !defined(ultrix) && !defined(__osf__)
/** use ALTCHARSET if termcap or terminfo knows how **/
if (cur->canUseACS) {
char *term, *chars;
char termname[20];
int count=0;
strcpy(termname, termtype);
/** VT100 terminals and above support alternate character set **/
if (strncasecmp(termname, "vt1", 3) == 0 ||
strncasecmp(termname, "vt2", 3) == 0 ||
strncasecmp(termname, "vt3", 3) == 0)
strcpy(termname, "vtxxx"); /* name in CURgraphicChars[] */
/*
* CURwgetstr is a replacement of getstr that allows editing of the string
* if the user types control codes we don't recognize, it's returned instead
* We assume that the incoming string is shorter than the max..
*/
int
CURwgetstr(CursesObj *cur, WINDOW *win, char *inputline, int maxlength, boolean hidden)
{
int pointer = 0;
int curpointer = 0;
int ch;
int y,x;
wstandout(win);
/*** Check to see if there's something in the inputline already ***/
while (inputline[pointer] != '\0') {
if (hidden)
waddch(win, '*');
else
waddch(win, inputline[pointer]);
pointer ++;
curpointer ++;
}
wrefresh(win);
for (;;) {
ch = CURwgetch(cur,win);
switch (ch) {
case '\n':
#ifdef CONTROLX
case '\030':
#endif
inputline[pointer] = '\0';
wstandend(win);
return(ch);
break;
case '\b': /*** backspace and delete ***/
if (curpointer > 0) {
char *cp;
/*
* This stuff is stolen and modified from hytelnet Thanks Earl!
*/
int
CURwgetch(CursesObj *cur, WINDOW *window)
{
int a, b, c;
if (ControlCpressed) {
return ('\007'); /** Control-C cancels us **/
}
if (signal(SIGINT, controlcJmp) == SIG_ERR)
perror("signal died:\n"), exit(-1);
if (setjmp(Jmpenv)) {
/* Note controlcJmp will reprime controlc and set flag*/
Debug("interruptable_wgetch triggered\r\n",NULL);
ControlCpressed = FALSE; /* Deal with return code, not flag*/
return('\007');
}
while (1) {
c = wgetch(window);
reprimeControlc();
switch (c) {
case -1: /* error usually means connection was closed.. */
CleanupandExit(-1);
break;
case 12: /* ^L */
case 18: /* ^R */
case 23: /* ^W */
/* redraw the screen */
#ifdef VMS
clearok(curscr, TRUE);
wrefresh(window);
#else
wrefresh(curscr);
#endif
/* don't return yet, get another keystroke */
break;
case 27: /* handle escape sequence */
b = wgetch(window);
if (b == '[' || b == 'O')
a = wgetch(window);
else
a = b;
switch (a) {
case 'A': c = KEY_UP; break;
case 'B': c = KEY_DOWN; break;
case 'C': c = KEY_RIGHT; break;
case 'D': c = KEY_LEFT; break;
case 'M': /* vt100 enter */
if (b == 'O')
c = KEY_ENTER;
break;
case 'Q': /* vt100 Help */
if (b == 'O')
c = KEY_HELP;
break;
case '2':
if (b == '[')
b = wgetch(window);
switch(b) {
case '8': /* vt200 Help */
if (wgetch(window) == '~')
c = KEY_HELP;
break;
case '9': /* vt200 Do */
if (wgetch(window) == '~')
c = KEY_ENTER;
break;
}
case '5': /* vt 200 prev. screen */
if (b == '[' && wgetch(window) == '~')
c = KEY_PPAGE;
break;
case '6': /* vt 200 next screen */
if (b == '[' && wgetch(window) == '~')
c = KEY_NPAGE;
break;
}
/* fall through to default to reassign certain keys */
default:
/* The many forms of the return key... */
if ((c == KEY_ENTER)|| (c=='\r'))
c = '\n'; /** SYSV curses Gack! **/
/* The many forms of backspace */
if (c == '\010' || c == '\177' || c == KEY_BACKSPACE)
return('\b');
return(c);
break;
} /* switch(c) */
} /* while(1) */
}
int
CURgetch(CursesObj *cur)
{
return(CURwgetch(cur, stdscr));
}
/*
* Resets the screen when a size change has happened
*/
/*
* Get one option displays a message, and gets a response
*
* If the Response has something in it, it is displayed and editable
*
* If the user wants to abort, GetOneOption returns a -1, otherwise it
* returns a 0
*/
int
CURGetOneOption(CursesObj *cur, char *Title, char *OptionName, char *Response)
{
int i;
Requestitem *items[2], item;
/*
* This is the old version of GetOneOption, for those times when the
* garsh darn terminal is just too gadblam slow :-)
*/
int
CUROldGetOneOption(CursesObj *cur, char *OptionName, char *Response)
{
int i;
/** Free memory **/
for (i=0; i <= numprompts; i++)
if (items[i])
free(items[i]);
free(items);
return(choice);
}
/*
* CURrequester takes an array of requestitems and does the right
* things with it..
*/
int
CURrequester(CursesObj *cur, char *Wintitle, Requestitem **items)
{
int BottomField;
int ch;
Requestitem *curitem;
int currentfield = 0;
int FieldsPerPage;
boolean Found;
int i,j,k;
int maxlength;
int maxpromptwidth = 0;
int numprompts = 0;
WINDOW *tempwin;
int TopField;
int WinLines;
int WinWidth = COLS - 1;
static char **RequestHelp = NULL;
if (RequestHelp == NULL) {
RequestHelp = (char**) malloc(sizeof(char*) * 8);
RequestHelp[0] = Gtxt(HELPCANCEL,190);
RequestHelp[1] = Gtxt("Tab, ^N : Move to next field",192);
RequestHelp[2] = Gtxt("^P : Move to previous field",193);
RequestHelp[3] = Gtxt("^F : Display next page",194);
RequestHelp[4] = Gtxt("^B : Display previous page",195);
RequestHelp[5] = Gtxt("^- : Help (^/ or ^7 may work)",196);
RequestHelp[6] = Gtxt(CXPROMPT1,197);
RequestHelp[7] = NULL;
}
/*** Find the number of prompts... and the max width ***/
while ((curitem = items[numprompts++]) != NULL) {
/*** Skip non editable prompts ***/
if (curitem->thing != CUR_LABEL) {
if (curitem->prompt && strlen(curitem->prompt) > maxpromptwidth)
maxpromptwidth = strlen(curitem->prompt);
} else {
if (currentfield == numprompts-1)
currentfield++;
}
}
/*** Add the window title, centered ***/
if (Wintitle != NULL)
CURcenterline(cur, tempwin, Wintitle, 0, WinWidth, TRUE);
/*** Display the form and allow the user to update it ***/
while (1) {
/*** Add the labels ***/
wmove(tempwin, WinLines - 2, 2);
waddstr(tempwin, Gtxt(FORMCANCEL,198));
if (items[currentfield]->thing == CUR_CHOICE)
waddstr(tempwin, Gtxt(" [Cycle Values: Space] [List Values: l]",199));
else {
#ifdef CONTROLX
waddstr(tempwin, " [Accept: ^X] ");
#else
waddstr(tempwin, " [Accept: Enter] ");
#endif
waddstr(tempwin, " [Next field: TAB] ");
waddstr(tempwin, " ");
}
/** Add the prompts and typing area **/
if (numprompts == 1 && items[0]->thing == CUR_PROMPT) {
wmove(tempwin, 2, 2);
waddstr(tempwin, items[0]->prompt);
/** Trim the stowage if necessary **/
if ((j = strlen(items[0]->stowage)) > maxlength)
while (j > maxlength)
(items[0])->stowage[--j] = '\0';
/** Add the stowage if it exists and its black space **/
wmove(tempwin, 4, 2);
wstandout(tempwin);
waddstr(tempwin, items[0]->stowage);
for (j=strlen(items[0]->stowage)+2; j < WinWidth-2; j++)
waddch(tempwin, ' ');
wstandend(tempwin);
}
else {
i = 0;
for (k = TopField; k <= BottomField ; k++) {
wmove(tempwin, 2 + i, 2);
if (items[k]->prompt) {
waddstr(tempwin, items[k]->prompt);
for (j = WinWidth-strlen(items[k]->prompt)-4; j>0;j--)
waddch(tempwin, ' ');
}
switch (items[k]->thing) {
case CUR_LABEL:
break;
case CUR_CHOICE:
/** Add the default **/
wmove(tempwin, 2 + i, maxpromptwidth + 4);
waddstr(tempwin,
items[k]->choices[items[k]->chooseitem]);
break;
case CUR_ASKL:
wordwrap = TRUE;
wmove(tempwin, 2 + i, 2);
wstandout(tempwin);
waddstr(tempwin, items[k]->stowage);
for (j = WinWidth - strlen(items[k]->stowage) - 4
; j > 0; j--)
waddch(tempwin, ' ');
wstandend(tempwin);
break;
default:
/** Add the black space for the stowage, **/
/** and the stowage, if it exists **/
wordwrap = FALSE;
wmove(tempwin, 2 + i, maxpromptwidth + 4);
wstandout(tempwin);
if (items[k]->thing == CUR_PASSWD)
for (j = strlen(items[k]->stowage); j > 0; j--)
waddch(tempwin, '*');
else if (items[k]->stowage)
waddstr(tempwin, items[k]->stowage);
#ifdef CONTROLX
if (ch == '\n') {
if (numprompts > 1) {
ch = '\t'; /* Treat as tab, next field */
} else {
ch = '\030'; /* Treat as control-X, accept */
}
}
#endif
switch (ch) {
case '\016':
case '\t':
/*** Move to next non-label field (tab) ***/
do {
currentfield++;
if (currentfield > numprompts - 1) {
TopField = 0;
BottomField = min(TopField + FieldsPerPage,
numprompts) - 1;
currentfield = TopField;
}
else if (currentfield > BottomField) {
TopField++;
BottomField++;
}
} while (items[currentfield]->thing == CUR_LABEL);
break;
case '\020':
/*** Move to the previous non-label field (back tab) ***/
do {
currentfield--;
if (currentfield < 0) {
currentfield = numprompts - 1;
TopField = max(0, numprompts - FieldsPerPage);
BottomField = currentfield;
}
else if (currentfield < TopField) {
TopField--;
BottomField--;
}
} while (items[currentfield]->thing == CUR_LABEL);
break;
case KEY_DOWN:
/*
* Move to the next non-label field on the current
* screen. If there is no such field, scroll down
* one line. If a non-label field is found, move
* to it, otherwise don't move. (Line down)
*/
if (currentfield == BottomField) {
TopField++;
BottomField++;
if (BottomField > numprompts - 1) {
TopField = 0;
BottomField = min(TopField + FieldsPerPage,
numprompts) - 1;
currentfield = TopField;
while (items[currentfield]->thing == CUR_LABEL)
currentfield++;
}
else if (items[BottomField]->thing != CUR_LABEL)
currentfield = BottomField;
}
else {
Found = FALSE;
for (i = currentfield + 1; i <= BottomField; i++)
if (items[i]->thing != CUR_LABEL) {
currentfield = i;
Found = TRUE;
break;
}
if (!Found) {
TopField++;
BottomField++;
if (BottomField > numprompts - 1) {
TopField = 0;
BottomField = min(TopField + FieldsPerPage,
numprompts) - 1;
currentfield = TopField;
while (items[currentfield]->thing == CUR_LABEL)
currentfield++;
}
else if (items[BottomField]->thing != CUR_LABEL)
currentfield = BottomField;
}
}
break;
case KEY_UP:
/*
* Move to the previous non-label field on the current
* screen. If there is no such field, scroll up
* one line. If a non-label field is found, move
* to it, otherwise don't move. (Line up)
*/
if (currentfield == TopField) {
TopField--;
BottomField--;
if (TopField < 0) {
TopField = max(0, numprompts - FieldsPerPage);
BottomField = numprompts - 1;
currentfield = BottomField;
while (items[currentfield]->thing == CUR_LABEL)
currentfield--;
}
else if (items[TopField]->thing != CUR_LABEL)
currentfield = TopField;
}
else {
Found = FALSE;
for (i = currentfield - 1; i >= TopField; i--)
if (items[i]->thing != CUR_LABEL) {
currentfield = i;
Found = TRUE;
break;
}
if (!Found) {
TopField--;
BottomField--;
if (TopField < 0) {
TopField = max(0, numprompts - FieldsPerPage);
BottomField = numprompts - 1;
currentfield = BottomField;
while (items[currentfield]->thing == CUR_LABEL)
currentfield--;
}
else if (items[TopField]->thing != CUR_LABEL)
currentfield = TopField;
}
}
break;
case '\006':
case KEY_NPAGE:
/*** Move down a page ***/
if (BottomField == numprompts - 1) {
currentfield = BottomField;
while (items[currentfield]->thing == CUR_LABEL)
currentfield--;
}
else {
BottomField = min(BottomField + FieldsPerPage,
numprompts) - 1;
TopField = max(0, BottomField - FieldsPerPage + 1);
if (currentfield < TopField) {
currentfield = TopField;
while (items[currentfield]->thing == CUR_LABEL)
currentfield++;
}
}
break;
case '\002':
case KEY_PPAGE:
/*** Move up a page ***/
if (TopField == 0) {
currentfield = 0;
while (items[currentfield]->thing == CUR_LABEL)
currentfield++;
}
else {
TopField = max(0, TopField - FieldsPerPage + 1);
BottomField = min(TopField + FieldsPerPage, numprompts) - 1;
if (currentfield > BottomField) {
currentfield = BottomField;
while (items[currentfield]->thing == CUR_LABEL)
currentfield--;
}
}
break;
case '\037':
case KEY_HELP:
CURDialog(cur, "Form Help", RequestHelp);
touchwin(tempwin);
break;
case '\007':
case -1:
/*** Cancel ***/
delwin(tempwin);
return(-1);
#ifdef CONTROLX
case '\030':
#else
case '\n':
#endif
delwin(tempwin);
return(0);
default:
if (wordwrap) {
char *p;
if ( currentfield == numprompts-1){
CURBeep(cur);
continue;
}
if (items[currentfield+1]->thing != CUR_ASKL ) {
CURBeep(cur);
continue;
}
/* we must go and find the last space in stowage and move
to next line */
p=strrchr(items[currentfield]->stowage,' ');
/* copy rest of string to next line */
if ( p != NULL ) {
char addit[2];
*addit = ch;
*(addit+1) = '\0';
strcat(p+1, addit);
strcpy(items[currentfield+1]->stowage,p+1);
/* now blank out those characters */
*p='\0';
wmove(tempwin, 2 + currentfield - TopField, 2);
wstandout(tempwin);
waddstr(tempwin, items[currentfield]->stowage);
for (j=strlen(items[currentfield]->stowage)+
maxpromptwidth+4; j < COLS-6; j++)
waddch(tempwin, ' ');
wstandend(tempwin);
}
currentfield++; /* go to next ASKL field */
if (currentfield > BottomField) {
TopField++;
BottomField++;
}
}
}
}
}
/*
* CURChoice takes a bunch of titles, throws them on the screen,
* and asks the user to choose one.
*
* Returns the number chosen, or -1 if the user cancels.
*
* Limitation: The number of choices must be less than 100.
*/
int
CURChoice(CursesObj *cur, char *WinTitle, char **Choices, char *Prompt, int DefaultChoice)
{
int BottomChoice;
int ch;
int ChoicesPerPage;
int CurrentChoice = 0;
int CurrentLine;
int CurrentPage;
int i;
char InBuf[3];
int j;
int k;
int MaxChoiceWidth = 0;
int NumChoices = 0;
int NumPages;
WINDOW *TempWin;
int TopChoice;
int WinLines;
int WinWidth;
static char ** ChoiceHelp = NULL;
if (ChoiceHelp == NULL) {
ChoiceHelp = (char**) malloc(sizeof(char*) * 10);
ChoiceHelp[0] = Gtxt(HELP2CANCEL,202);
ChoiceHelp[1] = Gtxt("Down, ^N : Move to next choice",203);
ChoiceHelp[2] = Gtxt("Up, ^P : Move to previous choice",204);
ChoiceHelp[3] = Gtxt("Space, ^F : Display next page",205);
ChoiceHelp[4] = Gtxt("b, ^B : Display previous page",206);
ChoiceHelp[5] = Gtxt("^ : Display first page",207);
ChoiceHelp[6] = Gtxt("$ : Display last page",208);
ChoiceHelp[7] = Gtxt("0-9 : Select a specific choice",209);
ChoiceHelp[8] = Gtxt("Enter : Select current choice",210);
ChoiceHelp[9] = NULL;
}
/*** Determine number of choices and verify it's within limits ***/
while (Choices[NumChoices] != NULL)
NumChoices++;
if (NumChoices == 0)
return(-1);
if (NumChoices > 99) {
CursesErrorMsg("More than 99 choices! Please gripe.");
return(-1);
}
/*** Display the dialog box and allow the user to make a choice ***/
while (1) {
/*** Add the current page of choices ***/
i = 0;
for (j = TopChoice; j <= BottomChoice; j++) {
wmove(TempWin, 2 + i, 8);
for (k = 0; k < WinWidth - 10; k++)
waddch(TempWin, ' ');
wmove(TempWin, 2 + i, 8);
wprintw(TempWin, "%2d.", j + 1);
wmove(TempWin, 2 + i, 12);
wprintw(TempWin, "%s", Choices[j]);
if (j == DefaultChoice)
waddstr(TempWin, Gtxt(" (default)",212));
i++;
}
/*** Add the cursor ***/
wmove(TempWin, CurrentLine, 3);
waddstr(TempWin, "-->");
/*** Update the screen ***/
wrefresh(TempWin);
/*** Let the user choose ***/
ch = CURwgetch(cur, TempWin);
switch(ch) {
case '\016':
case KEY_DOWN:
/*** Move down a line ***/
if (CurrentChoice == BottomChoice) {
TopChoice++;
BottomChoice++;
if (BottomChoice > NumChoices - 1) {
CurrentChoice = 0;
TopChoice = 0;
BottomChoice = min(TopChoice + ChoicesPerPage,
NumChoices) - 1;
}
else
CurrentChoice++;
}
else
CurrentChoice++;
break;
case '\020':
case KEY_UP:
/*** Move up a line ***/
if (CurrentChoice == TopChoice) {
TopChoice--;
BottomChoice--;
if (TopChoice < 0) {
CurrentChoice = NumChoices - 1;
TopChoice = max(0, NumChoices - ChoicesPerPage);
BottomChoice = CurrentChoice;
}
else
CurrentChoice--;
}
else
CurrentChoice--;
break;
case '\006':
case ' ':
case '+':
case KEY_NPAGE:
/*** Move down a page ***/
if (BottomChoice == NumChoices - 1)
CurrentChoice = BottomChoice;
else {
BottomChoice = min(BottomChoice + ChoicesPerPage,
NumChoices) - 1;
TopChoice = max(0, BottomChoice - ChoicesPerPage + 1);
CurrentChoice = max(TopChoice, CurrentChoice);
}
break;
case '\002':
case 'b':
case '-':
case KEY_PPAGE:
/*** Move up a page ***/
if (TopChoice == 0)
CurrentChoice = TopChoice;
else {
TopChoice = max(0, TopChoice - ChoicesPerPage + 1);
BottomChoice = min(TopChoice + ChoicesPerPage,
NumChoices) - 1;
CurrentChoice = min(CurrentChoice, BottomChoice);
}
break;
case '^':
/*** Move to top ***/
TopChoice = 0;
BottomChoice = min(TopChoice + ChoicesPerPage,
NumChoices) - 1;
CurrentChoice = TopChoice;
break;
case '\037':
case KEY_HELP:
case 'h':
case '?':
/*** Help ***/
CURDialog(cur, Gtxt("Choice Dialog Help",213), ChoiceHelp);
touchwin(TempWin);
break;
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': case '0':
/*** Literal ***/
InBuf[0] = ch;
InBuf[1] = '\0';
InBuf[2] = '\0';
/********************** Cruft for VMS follows ****************************/
#ifdef VMS
#include <descrip.h>
#include <iodef.h>
#include <ssdef.h>
#include <ttdef.h>
#include <tt2def.h>
#include <libclidef.h>
#include <smg$routines.h>
#include <smgdef.h>
#include <smgtrmptr.h>
#include <clidef.h>
#include <syidef.h>
#ifdef signal
#undef signal
#endif
#include <signal.h>
#ifdef system
#undef system
#endif
#include <processes.h>
#ifndef CLI$M_TRUSTED
#define CLI$M_TRUSTED 64 /* May not be in the compiler's clidef.h */
#endif
#define EFN 0 /* Event flag */
static int mask = LIB$M_CLI_CTRLY|LIB$M_CLI_CTRLT; /* ^Y and ^T */
static int old_msk; /* Saved control mask */
static short trap_flag = FALSE; /* TRUE if AST is set */
static $DESCRIPTOR (term_name, "SYS$INPUT:"); /* For channel assigns */
short term_chan; /* The channel */
static short first = TRUE; /* Terminal initialization flag */
struct char_buffer_type { /* Terminal characteristics */
char class;
char type;
unsigned short size;
unsigned long tchars;
unsigned long tchars2;
} oldbuf;
static int in_pos, in_len; /* For escape sequence */
static unsigned char buffer[20]; /* handling in w_getch */
boolean DidCleanup = FALSE; /* Exit handler flag */
static char VersionVMS[20]; /* Version of VMS */
/*
* Define local replacement for wgetch that returns the characters without
* having to set the terminal /pasthru, which screws up control-Y processing.
*/
static int w_getch(win)
int win;
{
int status;
unsigned short iosb[4];
if (in_pos < in_len)
return(buffer[in_pos++]);
status = sys$qiow (0, term_chan, IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
&iosb, 0, 0, &buffer, 1, 0, 0, 0, 0);
if ((status&1) == 1)
status = iosb[0];
if (status == SS$_PARTESCAPE) {
/* escape sequence in progress, fake a successful read */
status = 1;
}
if ((status&1) != 1)
exit(status);
in_pos = 1;
in_len = iosb[1] + iosb[3];
return (buffer[0]);
}
void
setterm_pas()
{
int status;
short iosb[4];
if(first)
VMSinit();
else
status = lib$disable_ctrl(&mask);
in_pos = 0; in_len = 0;
}
void
resetterm()
{
int status;
status = sys$qiow(0,term_chan,IO$_SETMODE,0,0,0,
&oldbuf,12,0,0,0,0);
status = lib$enable_ctrl(&old_msk);
}
/* VMS doesn't have termcap. Unfortunately, the code in this */
/* module uses termcap just a little bit (it really shouldn't) */
/* rather than doing everything through curses */
/* The following simulates tputs, but does not support padding */
int
tputs(register char *cp, int affcnt, int (*outc)())
{
while (*cp)
outc(*(cp++));
return(0);
}
/*
* VMSsignal -- F.Macrides 31-Jul-1993 (modification of my LYNX routine)
* Sets up AST for both Ctrl-C and Ctrl-Y, with system response to Ctrl-T
* disabled. If called with a sig other than SIGINT, it will use the C
* library's signal(sig, func).
* VMSsignal(SIGINT, SIG_DFL) is treated as a call to resetterm().
* Call VMSsignal(SIGINT, SIG_IGN) before system() calls to enable Ctrl-C
* and Ctrl-Y in the subprocess, and then call VMSsignal(SIG_INT, func)
* on return from the subprocess.
* For func's which do not invoke an exit, the func should reassert itself.
* The VMS C signal() calls do not fully emulate the Unix calls, and
* VMSsignal() is just a "helper", also not a full emulation.
*/
void
(*VMSsignal (sig, func)) (int)
int sig;
void (*func)();
{
int status;
short iosb[4];
static int SIG_IGN_flag;
/* pass all signals other than SIGINT to signal() */
if (sig != SIGINT) {
return(signal(sig, func));
}
/* if func is SIG_DFL, treat it as resetterm() */
if (func == SIG_DFL) {
resetterm();
return(SIG_DFL);
}
/* Clear any previous AST */
if (trap_flag) {
status = sys$dassgn (term_chan);
status = lib$enable_ctrl(&old_msk);
trap_flag = FALSE;
}
/* if func is SIG_IGN, leave the TT channel closed and the */
/* system response to interrupts enabled for system() calls */
if (func == SIG_IGN)
return(SIG_IGN);
/* if we get to here, we have a SIGINT func, so set the AST */
if(first)
VMSinit();
else {
status = sys$assign (&term_name, &term_chan, 0, 0);
status = lib$disable_ctrl(&mask);
}
status = sys$qiow (EFN, term_chan,
IO$_SETMODE|IO$M_CTRLCAST|IO$M_CTRLYAST,
&iosb, 0, 0,
func, SIGINT, 0, 0, 0, 0);
trap_flag = TRUE;
return(func);
}
/*
* VMSCURinit, VMSinit, VMSexit -- F.Macrides 12-Aug-1993
* Save termial characteristics at the time when gopher.c's Initialize()
* is called. Make sure they're retored and that cleanup is done if we
* exit via exit(-1)'s or ACCVIO's.
*/
void
VMSCURinit(cur)
CursesObj *cur;
{
int status, i;
short Type = 0;
long buf_siz = 20, len;
unsigned long Addr;
char ch, Name[20], cl[20], bl[20], so[20], se[20];
/*** Initialize the terminal, if we haven't already ***/
if(first)
VMSinit();
/*** Can't handle "unknown" terminal type ***/
if (oldbuf.type == 0) {
CURsetTerm(cur, "unknown");
return;
}
/*** Get the terminal table ready ***/
Type = (short) oldbuf.type;
status = smg$init_term_table_by_type (&Type, &Addr, &Name_desc);
if (!(status&1))
{
CURsetTerm(cur, "unknown");
return;
}
/*** Set the terminal name ***/
i = 0;
while ((Name[i++] != ' ') && i <= 20) ;
Name[--i] = '\0';
if (strlen(Name))
CURsetTerm(cur, Name);
else
CURsetTerm(cur, "VMS");
/*** Get the clearscreen code ***/
status = smg$get_term_data(&Addr, &SMG$K_ERASE_WHOLE_DISPLAY,
&buf_siz, &len, cl);
if (status&1) {
cl[len] = '\0';
CURsetCLS(cur, cl);
}
else
/*** Assume 7-bit ***/
CURsetCLS(cur, "\033[2J");
/*** Set the bell ***/
CURsetBell(cur, "\007");
/*** Set the highlight codes ***/
status = smg$get_term_data (&Addr, &SMG$K_BEGIN_BOLD,
&buf_siz, &len, so);
if (status&1) {
so[len] = '\0';
CURsetHighon(cur, so);
}
else
CURsetHighon(cur, "\033[1m");
status = smg$get_term_data (&Addr, &SMG$K_BEGIN_NORMAL_RENDITION,
&buf_siz, &len, se);
if (status&1) {
se[len] = '\0';
CURsetHighoff(cur, se);
}
else
CURsetHighoff(cur, "\033[m");
}
void
VMSinit()
{
int status;
static unsigned long condition;
static struct _exit_block {
unsigned long forward;
unsigned long address;
unsigned long zero;
unsigned long condition;
} exit_handler_block;
if(first) {
/* get a channel and save terminal parms if we haven't already */
status = sys$assign (&term_name, &term_chan, 0, 0 );
status = sys$qiow(0,term_chan,IO$_SENSEMODE,0,0,0,
&oldbuf,12,0,0,0,0);
first = FALSE;
status = lib$disable_ctrl(&mask, &old_msk);
/* declare the exit handler block */
status = sys$dclexh(&exit_handler_block);
if (status != SS$_NORMAL) {
printf("exit_status: %d", status);
}
/* Get the version of VMS */
if (VMSVersion(VersionVMS, 20) < 3)
/* Load zeros on error */
strcpy(VersionVMS, "V0.0-0");
}
}
void
VMSexit()
{
/*
* If we didn't get here via CleanupandExit(), it was via an
* exit(-1) or ACCVIO, so make *sure* we reset the terminal,
* then attempt a cleanup.
*/
if (!DidCleanup) {
fprintf(stderr,"\nPress RETURN to clean up and exit: ");
(void) getchar();
resetterm();
CleanupandExit(-1);
}
}
/*
* VMSVersion -- F.Macrides 09-Jan-1994
* Modification of UNZIP routine for getting VMS Version.
*/
int
VMSVersion(VerString, VerLen)
char *VerString;
int VerLen;
{
int status, i = SYI$_VERSION, verlen = 0;
struct dsc$descriptor version;
char *m;
status = lib$getsyi(&i, 0, &version, &verlen, 0, 0);
if (!(status&1) || verlen == 0)
return 0;
/* Cut out trailing spaces */
for (m=VerString+verlen, i=verlen-1; i > 0 && VerString[i] == ' '; --i)
*(--m) = '\0';
return strlen(VerString)+1; /* Transmit ending 0 too */
}
/*
* DCLsystem, spawn_DCLprocess, DCLspawn_exception -- F.Macrides 31-Jul-1993
* Exception-handler routines for enabling interrupts and Control-T
* during spawns when setjmp() has been established, and the parent
* passes a DCL CLI.
* F.Macrides 09-Jan-1994 -- spawn_DCLprocess includes TRUSTED flag for
* spawns with a command (but not spawns to DCL) if the version of
* OpenVMS/VAX requires it in captive accounts.
*/
int
DCLsystem(command)
char *command;
{
int status;
extern void controlc();
VMSsignal(SIGINT, SIG_IGN);
status = spawn_DCLprocess(command);
VMSsignal(SIGINT, controlc);
if ((status&1) != 1)
return(-1);
else
return(0);
}
int
spawn_DCLprocess(command)
char *command;
{
int status;
/** Keep DECC from complaining **/
struct dsc$descriptor_s command_desc;
command_desc.dsc$w_length = strlen(command);
command_desc.dsc$b_class = DSC$K_CLASS_S;
command_desc.dsc$b_dtype = DSC$K_DTYPE_T;
command_desc.dsc$a_pointer = command;
VAXC$ESTABLISH(DCLspawn_exception);
if (command == "")
status = lib$spawn(0);
else {
#ifndef __ALPHA /* OpenVMS/AXP v6.1 still doesn't have the TRUSTED flag ;( */
if(VersionVMS[1] >= '6')
/** Include TRUSTED flag **/
status = lib$spawn(&command_desc,0,0,&CLI$M_TRUSTED);
else
#endif
status = lib$spawn(&command_desc);
}
return(status);
}
unsigned int
DCLspawn_exception(sigarr, mecharr)
void *sigarr, *mecharr;
{
int status;
status = lib$sig_to_ret(sigarr, mecharr);
return(SS$_UNWIND);
}
#endif /* VMS */