Subversion Repositories shark

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 *
 *
 */


#include <stdio.h>
#include <stdlib.h>

#if defined(USE_NCURSES)

#include <curses.h>
#include <term.h>

#elif defined(USE_CONIO)

#include <conio.h>

/* for usleep() */
#include <unistd.h>
/* for sound(), nosound() */
#include <pc.h>

#else

#error USE_NCURSES or USE_CONIO must be defined

#endif

#include "hconf.h"

/*
 *
 * CONIO
 *
 */


#ifdef USE_CONIO

// with bold
#define DEFAULT_FG CYAN
#define DEFAULT_BG BLUE

#define NORMAL_FG BLACK
#define NORMAL_BG WHITE

// with bold
#define INVERSE_FG WHITE
#define INVERSE_BG BLUE

//with bold
#define BOX_BORDERFGU WHITE
#define BOX_BORDERBGU WHITE

#define BOX_BORDERFGD BLACK
#define BOX_BORDERBGD WHITE

#define BOX_FG BLACK
#define BOX_BG WHITE

#define SHADOW_FG BLACK
#define SHADOW_BG BLACK

#define TITLE_FG YELLOW
#define TITLE_BG WHITE

#define _KEY_OK     0x1b
#define _KEY_OK2    0x4b
#define _KEY_DOWN   0x50
#define _KEY_UP     0x48
#define _KEY_TOGGLE 0x0d
#define _KEY_HELP   '?'

/* (U-upper,L-lower) (L-left,R-right) */
#define _UL 'Ú'
#define _LL 'À'
#define _UR '¿'
#define _LR 'Ù'
#define _HH 'Ä'
#define _VV '³'

/* -- */

typedef struct tagWINDOW {
  int str,stc,nl,nc;
} WINDOW;

void _defaultcolor(WINDOW *w)
{
  textbackground(DEFAULT_BG);
  textcolor(DEFAULT_FG);
}

void _normal(WINDOW *w)
{
  textbackground(NORMAL_BG);
  textcolor(NORMAL_FG);
}

void _inverse(WINDOW *w)
{
  textbackground(INVERSE_BG);
  textcolor(INVERSE_FG);
}

void _shadow(WINDOW *w)
{
  textbackground(SHADOW_BG);
  textcolor(SHADOW_FG);
}

void _boxcolor(WINDOW *w)
{
  textbackground(BOX_BG);
  textcolor(BOX_FG);
}

void _titlecolor(WINDOW *w)
{
  textbackground(TITLE_BG);
  textcolor(TITLE_FG);
}

void _borderboxucolor(WINDOW *w)
{
  textbackground(BOX_BORDERBGU);
  textcolor(BOX_BORDERFGU);
}

void _borderboxdcolor(WINDOW *w)
{
  textbackground(BOX_BORDERBGD);
  textcolor(BOX_BORDERFGD);
}

/* -- */

struct text_info info;

#define _cols() info.screenwidth
#define _rows() info.screenheight

#define _cursor_invisible()   _setcursortype(_NOCURSOR)
#define _cursor_visible()     _setcursortype(_NORMALCURSOR)


#define _gotorc(w,r,c) gotoxy(w->stc+c+1,w->str+r+1)
#define _printw(w,fmt,args...) cprintf(fmt,##args)
#define _refresh(w)

#define _putch(w,c) putch(c)
#define _getch() getch()

void _clrscr(WINDOW *w)
{
  static char buffer[256];
  int r;
 
  memset(buffer,' ',sizeof(buffer));
  buffer[w->nc]='\0';
  for (r=0;r<w->nl;r++) {
    gotoxy(w->stc+1,w->str+r+1);
    cprintf("%s",buffer);
  }
}

void _clreol(WINDOW *w)
{
  int l;
  l=w->stc+w->nc-wherex();
  if (l>0)
    while (l-->0) putch(' ');    
}

void _bell(void)
{
  sound(2000);
  usleep(250000l);
  nosound();
}

/* -- */

WINDOW *_createwin(int str, int stc, int nlines, int cols)
{
  WINDOW *wnd;
  wnd=(WINDOW*)malloc(sizeof(WINDOW));
  if (wnd!=NULL) {
    wnd->str=str;
    wnd->stc=stc;
    wnd->nl=nlines;
    wnd->nc=cols;
  }
  return wnd;
}

#define _deletewin(w) free(w)

WINDOW *STDWIN;

void _initscreen(void)
{
  gppconio_init();
  gettextinfo(&info);
  STDWIN=_createwin(0,0,_rows(),_cols());
  _defaultcolor(STDWIN);
  clrscr();
}

void _endscreen(void)
{
  //clrscr();
}

#endif

/*
 *
 * NCURSES
 *
 */


#ifdef USE_NCURSES

// with bold
#define DEFAULT_FG COLOR_CYAN
#define DEFAULT_BG COLOR_BLUE

#define NORMAL_FG COLOR_BLACK
#define NORMAL_BG COLOR_WHITE

// with bold
#define INVERSE_FG COLOR_WHITE
#define INVERSE_BG COLOR_BLUE

//with bold
#define BOX_BORDERFGU COLOR_WHITE
#define BOX_BORDERBGU COLOR_WHITE

#define BOX_BORDERFGD COLOR_BLACK
#define BOX_BORDERBGD COLOR_WHITE

#define BOX_FG COLOR_BLACK
#define BOX_BG COLOR_WHITE

#define SHADOW_FG COLOR_BLACK
#define SHADOW_BG COLOR_BLACK

#define TITLE_FG COLOR_YELLOW
#define TITLE_BG COLOR_WHITE

#define _KEY_OK     0x1b
#define _KEY_OK2    'q'
#define _KEY_DOWN   KEY_DOWN
#define _KEY_UP     KEY_UP
#define _KEY_TOGGLE 0x0a
#define _KEY_HELP   '?'

/* -- */

#define _BACKGROUND 1
#define _NORMAL     2
#define _INVERSE    3
#define _BORDERBOXU 4
#define _BORDERBOXD 5
#define _BOX        6
#define _SHADOW     7
#define _TITLE      8
#define _DEFAULT    9

#define STDWIN stdscr

/* (U-upper,L-lower) (L-left,R-right) */
#define _UL ACS_BSSB
#define _LL ACS_SSBB        
#define _UR ACS_BBSS
#define _LR ACS_SBBS
#define _HH ACS_BSBS
#define _VV ACS_SBSB

void _defaultcolor(WINDOW *w)
{
  wattrset(w,COLOR_PAIR(_DEFAULT)|A_BOLD);
  wbkgdset(w,COLOR_PAIR(_DEFAULT)|A_BOLD);
}

void _normal(WINDOW *w)
{
  wattrset(w,COLOR_PAIR(_NORMAL));
  wbkgdset(w,COLOR_PAIR(_NORMAL));
}

void _inverse(WINDOW *w)
{
  wattrset(w,COLOR_PAIR(_INVERSE)|A_BOLD);
  wbkgdset(w,COLOR_PAIR(_INVERSE)|A_BOLD);
}

void _shadow(WINDOW *w)
{
  wattrset(w,COLOR_PAIR(_SHADOW));
  wbkgdset(w,COLOR_PAIR(_SHADOW));
}

void _boxcolor(WINDOW *w)
{
  wattrset(w,COLOR_PAIR(_BOX));
  wbkgdset(w,COLOR_PAIR(_BOX));
}

void _titlecolor(WINDOW *w)
{
  wattrset(w,COLOR_PAIR(_TITLE)|A_BOLD);
  wbkgdset(w,COLOR_PAIR(_TITLE)|A_BOLD);
}

void _borderboxucolor(WINDOW *w)
{
  wattrset(w,COLOR_PAIR(_BORDERBOXU)|A_BOLD);
  wbkgdset(w,COLOR_PAIR(_BORDERBOXU)|A_BOLD);
}

void _borderboxdcolor(WINDOW *w)
{
  wattrset(w,COLOR_PAIR(_BORDERBOXD));
  wbkgdset(w,COLOR_PAIR(_BORDERBOXD));
}

/* -- */

#define _cursor_invisible()   putp(cursor_invisible)
#define _cursor_visible()     {putp(cursor_visible);putp(cursor_normal);}

#define _cols() COLS
#define _rows() LINES
#define _gotorc(w,r,c) wmove(w,r,c)

#define _printw(w,fmt,args...) wprintw(w,fmt,##args)
#define _refresh(w) wrefresh(w)

#define _putch(w,c) waddch(w,c)
#define _getch() getch()
#define _clreol(w) wclrtoeol(w)
#define _clrscr(w) wclear(w)

#define _bell() addch('\07');

/* -- */

void _initscreen(void)
{
  initscr();
  start_color();
  init_pair(_BACKGROUND,DEFAULT_BG,DEFAULT_BG);
  init_pair(_DEFAULT,DEFAULT_FG,DEFAULT_BG);
  init_pair(_NORMAL,NORMAL_FG,NORMAL_BG);
  init_pair(_INVERSE,INVERSE_FG,INVERSE_BG);
  init_pair(_BORDERBOXU,BOX_BORDERFGU,BOX_BORDERBGU);
  init_pair(_BORDERBOXD,BOX_BORDERFGD,BOX_BORDERBGD);
  init_pair(_BOX,BOX_FG,BOX_BG);
  init_pair(_SHADOW,SHADOW_FG,SHADOW_BG);
  init_pair(_TITLE,TITLE_FG,TITLE_BG);
  bkgdset(COLOR_PAIR(_BACKGROUND));
  clear();
  cbreak(); /* input one char at time (don't wait for \n) */
  noecho();
  keypad(stdscr,TRUE);
  _normal(stdscr);
  _cursor_invisible();
  refresh();
}

void _endscreen(void)
{
  _cursor_visible();
  refresh();
  endwin();
}

WINDOW *_createwin(int str, int stc, int nlines, int cols)
{
  WINDOW *wnd;
  wnd=newwin(nlines,cols,str,stc);
  if (wnd!=NULL) {
    //wbkgdset(wnd,COLOR_PAIR(_BACKGROUND));
    //wclear(wnd);
    //_normal(wnd);
  }
  return wnd;
}

#define _deletewin(w) delwin(w)

#endif

/*
 *
 *
 *
 */


static void whichcolor(WINDOW *wnd, int up, int inv)
{
  if (((inv==1)&&(up==1))||((inv==0)&&(up==0))) _borderboxdcolor(wnd);
  else _borderboxucolor(wnd);
}

void _settitle(WINDOW *wnd,
               int sy, int sx,
               int nlines, int cols,
               int bordy, int bordx,
               char *title,
               int shad, int inv)
{
  int x;

  sx-=bordx+1;
  sy-=bordy+1;
  cols+=2*(bordx+1);
  nlines+=2*(bordy+1);

  whichcolor(wnd,1,inv);
  _gotorc(wnd,sy,sx+1);
  for (x=0;x<cols-2;x++) _putch(wnd,_HH);

  if (title!=NULL) {
    _titlecolor(wnd);
    _gotorc(wnd,sy,sx+(cols-strlen(title)-2)/2);
    _printw(wnd," %s ",title);

    _normal(wnd);
    _gotorc(wnd,sy+2,sx+2);
    _printw(wnd,"use <ESC> to exit, <ENTER> to enter/toggle,");
    _gotorc(wnd,sy+3,sx+2);
    _printw(wnd,"arrows keys to move");
  }


  _refresh(wnd);
}

void _box(WINDOW *wnd,
          int sy, int sx,
          int nlines, int cols,
          int bordy, int bordx,
          char *title,
          int shad, int inv)
{
  int x,y;

  sx-=bordx+1;
  sy-=bordy+1;
  cols+=2*(bordx+1);
  nlines+=2*(bordy+1);
 
  {
    static char blanks[180];
    memset(blanks,' ',sizeof(blanks));
    blanks[cols]='\0';
    _boxcolor(wnd);
    for (y=0;y<nlines;y++) {
      _gotorc(wnd,sy+y,sx);
      _printw(wnd,"%s",blanks);
    }
  }
 
  whichcolor(wnd,1,inv);
  _gotorc(wnd,sy,sx);
  _putch(wnd,_UL);
  for (x=0;x<cols-2;x++) _putch(wnd,_HH);
  whichcolor(wnd,0,inv);
  _putch(wnd,_UR);

  for (y=1;y<nlines-1;y++) {
    whichcolor(wnd,1,inv);
    _gotorc(wnd,sy+y,sx);
    _putch(wnd,_VV);
    whichcolor(wnd,0,inv);
    _gotorc(wnd,sy+y,sx+cols-1);
    _putch(wnd,_VV);
    if (shad) {
      _shadow(wnd);
      _putch(wnd,' ');
      _putch(wnd,' ');
    }
  }

  whichcolor(wnd,1,inv);
  _gotorc(wnd,sy+nlines-1,sx);
  _putch(wnd,_LL);
  whichcolor(wnd,0,inv);
  for (x=0;x<cols-2;x++) _putch(wnd,_HH);
  _putch(wnd,_LR);
  if (shad) {
    _shadow(wnd);
    _putch(wnd,' ');
    _putch(wnd,' ');
  }

  if (shad) {
    _shadow(wnd);
    _gotorc(wnd,sy+nlines,sx+1);
    for (x=0;x<cols+1;x++) _putch(wnd,' ');
  }

  sx+=bordx+1;
  sy+=bordy+1;
  cols-=2*(bordx+1);
  nlines-=2*(bordy+1);

  _settitle(wnd,sy,sx,nlines,cols,bordy,bordx,title,shad,inv);

  /* refresh made by _settitle() */
}

void showtitle(char *s);

/* -- */


void showbool(WINDOW *wnd, struct menuentry *ptr)
{
  struct variable *var;
  char ch;
  var=ptr->x.bool.var;  
  if (!strcmp(var->value,"y")) ch='*';
  else ch=' ';
  _printw(wnd,"[%c] %s",ch,ptr->x.bool.text);
  _normal(wnd);
  _clreol(wnd);
}

void showtristate(WINDOW *wnd, struct menuentry *ptr)
{
  struct variable *var;
  char ch;
  var=ptr->x.bool.var;  
  if (!strcmp(var->value,"y")) ch='*';
  else if (!strcmp(var->value,"n")) ch=' ';
  else ch='M';
  _printw(wnd,"<%c> %s",ch,ptr->x.bool.text);
  _normal(wnd);
  _clreol(wnd);
}

void showchoice(WINDOW *wnd, struct menuentry *ptr)
{
  if (strcmp(ptr->x.choice.act->var->value,"y")) {
    /* well.. sometimes reading an old config.h can cause act pointer */
    /* to be bad :-( */
    struct choice *p;
    p=ptr->x.choice.list;
    while (p!=NULL) {
      if (!strcmp(p->var->value,"y")) {
        ptr->x.choice.act=p;
        break;
      }
      p=p->next;
    }
  }

  _printw(wnd,"    %s (%s)",ptr->x.choice.text,ptr->x.choice.act->text);
  _normal(wnd);
  _clreol(wnd);
}

void showrange(WINDOW *wnd, struct menuentry *ptr)
{
  _printw(wnd,"    %s (%s)",ptr->x.range.text,ptr->x.range.var->value);
  _normal(wnd);
  _clreol(wnd);
}

void showsubmenu(WINDOW *wnd, struct menuentry *ptr)
{
  _printw(wnd,"    %s --->",ptr->x.submenu.text);
  _normal(wnd);
  _clreol(wnd);
}

void showseparator(WINDOW *wnd, struct menuentry *ptr)
{
  _printw(wnd,"    ***********************    ");
  _normal(wnd);
  _clreol(wnd);
}

/* -- */

int nmax; // numero linee massimo

void showmenuentries(WINDOW *wnd,struct menuentry *ptr, int r, int c, int rcur)
{
  int i;

  i=0;
  while (ptr!=NULL) {
    _gotorc(wnd,r,c);
    if (r==rcur) _inverse(wnd);
    else _normal(wnd);
    r++;
    switch(ptr->type) {
      case RANGEENTRY:
        showrange(wnd,ptr);
        break;
      case BOOLENTRY:
        showbool(wnd,ptr);
        break;
      case TRISTATEENTRY:
        showtristate(wnd,ptr);
        break;
      case CHOICEENTRY:
        showchoice(wnd,ptr);
        break;
      case SUBMENUENTRY:
        showsubmenu(wnd,ptr);
        break;
      case SEPARATORENTRY:
        showseparator(wnd,ptr);
        break;
      default:
        _printw(wnd,"@@@");
        break;
    }
    ptr=ptr->n;
    i++;
    if (i==nmax) return;
  }
}

/* --- */

struct menuentry *expandcase(struct menuentry *menuent);
struct menuentry *expandmenu(struct menuentry *menuent);

struct menuentry *expandcase(struct menuentry *menuent)
{
  struct _case *list;
  list=menuent->x._case.list;
  while (list!=NULL) {
    if (!strcmp(list->value,menuent->x._case.var->value)) {      
      return expandmenu(list->list);
    }
    list=list->next;
  }
  return NULL;
}

int nument;

struct menuentry *expandmenu(struct menuentry *menuent)
{
  struct menuentry *start,*ptr,*ent,*prev,*p;
  int ne;

  ne=0;
  ptr=menuent;
  prev=NULL;
  start=NULL;
  while (ptr!=NULL) {
    switch(ptr->type) {

    case CASEENTRY:
      ent=expandcase(ptr);
      if (ent==NULL) {
        if (prev!=NULL) prev->n=ptr->next;
        ptr=ptr->next;
        break;
      }
      if (start==NULL) start=ent;

      if (prev!=NULL) prev->n=ent;
      ent->p=prev;
      p=ent;
      while (p->n!=NULL) p=p->n;
      p->n=ptr->next;

      prev=p;
      ptr=ptr->next;
      break;

    default:
      if (start==NULL) start=ptr;
      ne++;

      ptr->p=prev;
      ptr->n=ptr->next;
     
      prev=ptr;
      ptr=ptr->next;
      break;
    }
  }

  nument+=ne;
  return start;
}

/* -- */

#define MUSTREDISPLAY 0x01
#define MUSTREBUILD   0x02

int showmenu(WINDOW *wnd, struct menu *menu);
int showchoicewnd(WINDOW *wnd, struct menuentry *menu);
int showrangewnd(WINDOW *wnd, struct menuentry *menu);

int enteron(WINDOW *wnd,struct menuentry *ptr)
{
  struct variable *var;

  switch(ptr->type) {

  case BOOLENTRY:
    var=ptr->x.bool.var;
    if (*var->value=='y') *var->value='n';
    else *var->value='y';
    if (var->flags&FLAG_M) return MUSTREBUILD;
    break;

  case TRISTATEENTRY:
    var=ptr->x.tristate.var;
    if (*var->value=='y') *var->value='n';
    else if (*var->value=='n') *var->value='m';
    else *var->value='y';
    if (var->flags&FLAG_M) return MUSTREBUILD;
    break;

  case RANGEENTRY:
    return showrangewnd(wnd,ptr)|MUSTREDISPLAY;

  case CHOICEENTRY:
    return showchoicewnd(wnd,ptr)|MUSTREDISPLAY;

  case SUBMENUENTRY:
    return showmenu(wnd,ptr->x.submenu.menu)|MUSTREDISPLAY;

  default:
    _bell();
    break;
  }

  return 0;
}

/* --- */

int SC=9;
int SR=9;
int NL=36;
int NC=61;
int BR=0;
int BC=4;

/* --- */

/* sigh :-( */
static struct choice *findprev(struct choice *list, struct choice *cur)
{
  struct choice *c,*p;
  c=list;
  p=NULL;
  while (c!=NULL) {
    if (c==cur) return p;
    p=c;
    c=c->next;
  }
  return NULL;
}

int showchoicewnd(WINDOW *oldwnd, struct menuentry *ent)
{
  WINDOW *wnd;
  struct choice *first; // first menuentry of the list
  struct choice *cur;   // selected menuentry
  struct choice *fline; // menuentry to show on the first line
  struct choice *p;
  int ch;
  int rcur;
  int i,r,c;
  int ret;
  int numcho;
 
  ret=MUSTREDISPLAY;
 
  numcho=ent->x.choice.numchoices;
  _box(oldwnd,(NL-2-numcho)/2,5,numcho,NC-10,1,1,NULL,0,0);
  wnd=_createwin(SR+(NL-2-numcho)/2,SC+5,numcho,NC-10);
  _normal(wnd);
  _clrscr(wnd);

  first=fline=cur=ent->x.choice.list;
  rcur=0;

  //showtitle(ent->x.choice.text);
  _clrscr(wnd);
 
  for (;;) {
 
    r=c=0;

    p=fline;
    i=0;
    while (p!=NULL) {
      _gotorc(wnd,r,c);
      if (r==rcur) _inverse(wnd);
      else _normal(wnd);
      r++;

      _printw(wnd,"(%c) %s",p==ent->x.choice.act?'X':' ',p->text);
      _clreol(wnd);
     
      p=p->next;
      i++;
      if (i==nmax) break;
    }

    _refresh(wnd);

    ch=getch();
    switch (ch) {

    case _KEY_OK:
    case _KEY_OK2:
      return ret;

    case _KEY_DOWN:
      if (cur->next==NULL) break;
      cur=cur->next;
      if (rcur<NL-1) {
        rcur++;
        break;
      }
      fline=fline->next;
      break;

    case _KEY_UP:
      p=findprev(ent->x.choice.list,cur);
      if (p==NULL) break;
      cur=p;
      if (rcur!=0) {
        rcur=rcur--;
        break;
      }
      fline=findprev(ent->x.choice.list,fline);
      break;

    case _KEY_TOGGLE:
      if ((ent->x.choice.act->var->flags&FLAG_M)||(cur->var->flags&FLAG_M))
        ret|=MUSTREBUILD;
      *(ent->x.choice.act->var->value)='n';
      ent->x.choice.act=cur;
      *(ent->x.choice.act->var->value)='y';
      break;         
    }    
  }
}

int showrangewnd(WINDOW *wnd, struct menuentry *ent)
{
  WINDOW *nw;
  int ret;
  int ch;
  int val;

  ret=MUSTREDISPLAY;

  _box(wnd,(NL-3)/2,5,1,NC-10,1,1,NULL,0,0);
  nw=_createwin(SR+(NL-3)/2,SC+5,1,NC-10);
  _normal(nw);
  _clrscr(nw);
 
  val=atoi(ent->x.range.var->value);
  for (;;) {
 
    _normal(nw);
    _gotorc(nw,0,0);
    _printw(nw,"    %s : %8i",ent->x.range.text,val);
    _clreol(nw);
    _refresh(nw);

    ch=getch();
    switch (ch) {

    case _KEY_OK:
    case _KEY_OK2:
    case _KEY_TOGGLE:
      {
        char buffer[256];
        sprintf(buffer,"%i",val);
        copystring(&ent->x.range.var->value,buffer);
      }
      _deletewin(nw);
      return ret;

    case _KEY_DOWN:
      if (val>ent->x.range.minval) val--;
      break;

    case _KEY_UP:
      if (val<ent->x.range.maxval) val++;
      break;

    }    
  }
}






int showhelpwin(WINDOW *wnd, struct menuentry *ent)
{
  struct variable *var;
  FILE *fin;
  char buffer[256];
  WINDOW *nw;
  int ret;
  int ch;
  int flag;
 
  ret=MUSTREDISPLAY;

  _box(wnd,(NL-3)/2,5,1,NC-10,1,1,NULL,0,0);
  nw=_createwin(SR+(NL-3)/2,SC+5,1,NC-10);
  _normal(nw);
  _clrscr(nw);
 
  _normal(nw);
  _gotorc(nw,0,0);

  switch(ent->type) {
    case BOOLENTRY:      var=ent->x.bool.var; break;
    case SUBMENUENTRY:   var=NULL; break;
    case TRISTATEENTRY:  var=ent->x.tristate.var; break;
    case CHOICEENTRY:    var=ent->x.choice.act->var; break;
    case CASEENTRY:      var=NULL; break;
    case RANGEENTRY:     var=ent->x.range.var; break;
    case SEPARATORENTRY: var=NULL; break;
    default:             var=NULL;
  }

  if (var==NULL) goto END;
 
  fin=fopen(helpfilename,"rt");
  if (fin!=NULL) {

    if (varhelp[findvarindex(var)]==0) goto END;    
    fseek(fin,varhelp[findvarindex(var)],SEEK_SET);
   
    flag=0;
    while (fgets(buffer,sizeof(buffer),fin)!=NULL) {
      if (*buffer=='#') continue;
      if (*buffer=='@') {
        if (flag) break;
        continue;
      }
      _gotorc(nw,flag,0);
      _printw(nw,"%s",buffer);
      flag++;
    }
    fclose(fin);
  }
   
  _clreol(nw);
  _refresh(nw);

  ch=getch();
 
END:    
  _deletewin(nw);
  return ret;
}







int showmenu(WINDOW *wnd, struct menu *menu)
{
  struct menuentry *first; /* first menuentry of the list */
  struct menuentry *cur;   /* selected menuentry */
  struct menuentry *fline; /* menuentry to show on the first line */
  int redo;
  int ch;
  int rcur;
  int ret;

  first=fline=cur=NULL;
  rcur=0;
  redo=1;
  ret=MUSTREDISPLAY;

  for (;;) {
    if (redo&MUSTREBUILD) redo|=MUSTREDISPLAY;
    ret|=redo;
    if (redo&MUSTREBUILD) {
      fline=NULL;
     
    }
    if (redo&MUSTREDISPLAY) {
      nument=0;
      first=expandmenu(menu->entries);
      if (fline==NULL) {
        fline=first;
        if (cur==NULL) {
          cur=fline;
          rcur=0;
        }
      }
      nmax=NL;
      showtitle(menu->title);
      _normal(wnd);
      _clrscr(wnd);
      redo=0;
    }
    showmenuentries(wnd,fline,0,0,rcur);
    _refresh(wnd);

    ch=getch();
    switch (ch) {

      case _KEY_OK:
      case _KEY_OK2:
        return ret;

      case _KEY_DOWN:
        if (cur->n==NULL) break;
        cur=cur->n;
        if (rcur<NL-1) {
          rcur++;
          break;
        }
        fline=fline->n;
        break;

      case _KEY_UP:
        if (cur->p==NULL) break;
        cur=cur->p;
        if (rcur!=0) {
          rcur=rcur--;
          break;
        }
        fline=fline->p;
        break;

      case _KEY_TOGGLE:
        redo=enteron(wnd,cur);      
        break;       
     
      case _KEY_HELP:
        redo=showhelpwin(wnd,cur);
        break;
       
      default:
        /*
          _normal(STDWIN);
          _gotorc(STDWIN,0,0);
          _printw(STDWIN,"%04x",ch);
          _refresh(STDWIN);
          */

    }    
   
  }

}

void showtitle(char *s)
{
  _settitle(STDWIN,SR-6,SC-2,NL+8,NC+4,BR,BC,s,1,0);
}

/*
 *
 */


int show(void)
{
  WINDOW *wnd;
  int i;

  _initscreen();
  _cursor_invisible();

  SC=9;
  SR=9;
  NL=_rows()-5-SR-BR*2;
  NC=_cols()-2-SC-BC*2;
  BR=0;
  BC=4;

  _defaultcolor(STDWIN);
  _gotorc(STDWIN,0,0);
  if (caption!=NULL) _printw(STDWIN," %s",caption);
  _gotorc(STDWIN,1,1);
  for (i=0;i<_cols()-2;i++) _putch(STDWIN,_HH);

  _box(STDWIN,SR-6,SC-2,NL+8,NC+4,BR,BC,NULL,1,0);
  _box(STDWIN,SR,SC,NL,NC,BR,BC,NULL,0,1);
  wnd=_createwin(SR,SC,NL,NC);

  showmenu(wnd,mainmenu);

  _cursor_visible();
  _refresh(STDWIN);
  _endscreen();

  return 0;
}