/***************************************************************************
 *                                                                         *
 *   BBSMTREE.C                                                            *
 *                                                                         *
 *   Copyright (c) 1992-1997 Galacticomm, Inc.     All rights reserved.    *
 *                                                                         *
 *   This is the menu tree viewer/editor.                                  *
 *                                                                         *
 *                                    - S. Brinker    02/11/92             *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "integrou.h"
#include "edtoff.h"
#include "mdlogic.h"
#include "protstuf.h"
#include "excphand.h"

#define FILREV "$Revision: 21 $"

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * CODE NOTE |                                                             *
 *------------                                                             *
 *   This is the file layout for WGSMENUS.IDX:                             *
 *                                                                         *
 *   %d %d %d                 .... &nstumps,&timaxx,&timaxy                *
 *   %s %d %d %d %d %d %d %d  .... &name,&parent,&child,&upsib,&dnsib,     *
 *                                 &tx,&ty,&flags                          *
 *   %s %d %d %d %d %d %d %d  .... &name,&parent,&child,&upsib,&dnsib,     *
 *                                 &tx,&ty,&flags                          *
 *   (repeat 'til EOF)                                                     *
 *                                                                         *
 *   NOTE: All stumps that point to the imaginary "Master" stump or        *
 *         non-existent children or siblings are set to point to           *
 *         stumps[0]; stumps[0] is therefore not a real page, can't        *
 *         be edited, and should generally be ignored.                     *
 *                                                                         *
 *         "TOP" should be stumps[1].                                      *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

struct stump {                     /* menu tree "stump" structure          */
     CHAR name[PNMSIZ];            /*   name of page (Btrieve key)         */
     INT parent;                   /*   index to parent                    */
     INT child;                    /*   index to child                     */
     INT upsib;                    /*   index to up sibling                */
     INT dnsib;                    /*   index to down sibling              */
     INT tx,ty;                    /*   (x,y) location in tree image       */
     INT flags;                    /*   various bit flags                  */
};

#define ISAUTO      0x0001         /* this is an auto-branch page          */
#define ISFILE      0x0002         /* this is a display-file page          */
#define ISMODU      0x0004         /* this is a module-link page           */
#define ISCSMD      0x0008         /* this is a C/S module-link page       */

#define TWULX       1              /* tree image window upper left x coord */
#define TWULY       1              /* tree image window upper left y coord */
#define TWXSIZ      78             /* x size of tree image window          */
#define TWYSIZ      21             /* y size of tree image window          */
#define TWLRX       TWULX+TWXSIZ-1 /* tree image window lower right x coord*/
#define TWLRY       TWULY+TWYSIZ-1 /* tree image window lower right x coord*/

#define TREATR      0x1F           /* tree image drawing attribute         */
#define IASATR      0x1E           /* auto-branch page attribute           */
#define IFSATR      0x1D           /* display-file page attribute          */
#define IMSATR      0x1A           /* module-link page attribute           */
#define ICSATR      0x1B           /* C/S module-link page attribute       */

#define ININOS      2              /* # of stumps to initialize a new tree */
#ifndef DEBUG
#define DFTMXS      6500           /* default max # of stumps allowed      */
#else
#define DFTMXS      650            /* debug mode default, for speed        */
#endif

INT maxstp=DFTMXS;                 /* maximum number of stumps allowed     */

VOID *stpblok=NULL;                /* alcblok()'d stump array              */
INT nstumps;                       /* number of stumps in stumps[] array   */
INT curstump;                      /* current stump # we're working with   */
DFAFILE *mpbb;                     /* pointer to Btrieve WGSMENU2.DAT file */
struct mnupag *workpag,            /* working copy of a menu page record   */
              *savepag;            /* backup of a menu page (for ESC stuff)*/
CHAR **avmlst;                     /* pointer to list of available modules */
CHAR **avmlstaa;                   /* pointer to list of avail A/A modules */
CHAR **avmlstcs;                   /* pointer to list of avail C/S modules */
INT mtdone=0;                      /* when menutree is done, this equals 1 */
INT timaxx,timaxy;                 /* max sizes of tree image x & y coords */
INT tiulx=0,tiuly=0;               /* upper-left corner of image displayed */
INT curx=TWULX,cury=TWULY;         /* current (x,y) location on screen     */
INT msoidx=0;                      /* index into menu select options       */
INT filecas;                       /* flags for edtval()                   */
GBOOL csedit=FALSE;                /* use C/S side of menus                */

#define   MAXEXS    50             /* maximum # of separate file extensions*/
#define   OFNSIZ    13             /* file name size (no path prefix)      */

CHAR *mdfnam[4]={                  /* menu/module/file for choose window   */
     "Menu Page",
     "Module Page",
     "File Page",
     NULL
};

CHAR *csmdfnam[5]={                /* menu/AAmodule/file/CSmodule          */
     "Menu Page",
     "C/S-mode Module Page",
     "File Page",
     "Terminal-mode Module Page",
     NULL
};

#define MNPIDX      0              /* indexes into mdfnam[] array          */
#define MDPIDX      (csedit ? 3 : 1)
#define FIPIDX      2
#define CSMIDX      (csedit ? 1 : 3)

#define NSCNS       6+7            /* number of screens in screen table    */
extern CHAR scntbl[NSCNS][GVIDSCNSIZ];/* table of screens in memory*/
                                   /*   screens 0-5 def'd in MDLOGIC.C     */
#define MAISCN      6              /*   main menu tree screen              */
#define SEASCN      7              /*   search menu tree screen            */
#define EMNSCN      8              /*   edit menu page screen              */
#define MESSCN      9              /*   miscellaneous editing screen(s)    */
#define EFMSCN     10              /*   edit file or module pages screen   */
#define MLTLNG     11              /*   multilingual-related windows scn   */
#define CSMSCN     12              /*   C/S edit menu page screen          */

CHAR *tmpscn;                      /* temporary screen memory              */

#define YONSIZ      4              /* size of yes/no edtval() fields       */

                                   /* std. 1st 4 states for editing pages  */
#define PGNSTT      0              /* editing page name state              */
#define MDFSTT      1              /* menu, module, or file? state         */
#define AGCSTT      2              /* allow go commands? state             */
#define K4GSTT      3              /* key for go commands state            */

#define SPLITN      13             /* split menu options after this        */
#define scx()       (msoidx < SPLITN ? 7 : 43)
#define msy()       (msoidx < SPLITN ? 9+msoidx+1 : 9+msoidx-SPLITN+1)
#define sdx()       (msoidx < SPLITN ? 9 : (csedit ? 43 : 45))

#define in(n,a,b)        ((n) >= (a) && (n) <= (b))

#define tx2sx(a)         ((a)-tiulx+TWULX)
#define ty2sy(a)         ((a)-tiuly+TWULY)
#define sx2tx(a)         (tiulx+(a)-TWULX)
#define sy2ty(a)         (tiuly+(a)-TWULY)

INT bldchl(CHAR **list,CHAR *pnam,INT *lnglst);
INT canedit(struct lingo *edtlng);
VOID frechl(CHAR **list,INT num);
INT newext(CHAR **list,INT num,CHAR *ext);
struct stump *stpoff(INT stpnum);

VOID editpage(VOID);
INT editfile(INT edfstt);
INT editmodu(INT eddstt);
INT editcsmod(INT eddstt);
INT editmenu(INT edmstt);
VOID updpag(VOID);
GBOOL valesc(INT c,CHAR *stg);
GBOOL valesd(INT c,CHAR *stg);
GBOOL valttl(INT c,CHAR *stg);
VOID editmso(CHAR dstart);
GBOOL isvslc(INT c,CHAR *stg);
INT mcnpag(VOID);
INT crnpag(VOID);
INT xistsc(INT c);
VOID movemso(VOID);
VOID shuflo(INT fromsl,INT tosl);
VOID delmso(VOID);
VOID updk4g(INT x,INT y);
VOID uemlttl(CHAR *emlstg,CHAR *ttlstg);
VOID mdintf(VOID);
INT bldchl(CHAR **list,CHAR *pnam,INT *lnglst);
INT canedit(struct lingo *edtlng);
VOID frechl(CHAR **list,INT num);
INT newext(CHAR **list,INT num,CHAR *ext);
INT gonstt(INT upstt,INT dnstt,INT lfstt,INT rtstt);
INT gonmso(INT curstt);
VOID rdomso(VOID);
VOID rmsobx(VOID);
VOID amsobx(VOID);
VOID gotopg(VOID);
VOID seapag(VOID);
struct stump *ismtch(CHAR *seastg,struct stump *sp);
VOID addpg(VOID);
VOID delpg(VOID);
VOID orphan(struct stump *sptr);
VOID renparto(CHAR *newpar,INT paridx);
VOID losedp(struct stump *sptr);
VOID dxystu(struct stump *sptr,INT dx,INT dy);
VOID cpmsonam(VOID);
struct stump *nearups(VOID);
struct stump *neardns(VOID);
VOID jmp2txy(INT jx,INT jy,INT minlen);
INT rvtcurs(VOID);
VOID rgtcurs(VOID);
VOID drawtree(INT ultx,INT ulty,INT lrtx,INT lrty);
INT txinsx(struct stump *sp,INT lxb,INT rxb);
VOID drawstump(struct stump *stuptr,INT lxb,INT rxb,INT regatr);
INT stuatr(struct stump *stuptr);
VOID clrarea(INT culx,INT culy,INT clrx,INT clry,CHAR *clrstg);
VOID addstump(INT parent,INT upsib,CHAR *name,INT flags);
VOID shiftt(INT fromy,INT xamt,INT yamt);
VOID movstump(struct stump *sp,INT newtx,INT newty,INT parent,INT upsib,
      INT dnsib);
struct stump *cpystump(struct stump *sptr);
VOID cpysutl(struct stump *sp,INT paridx,INT upsidx);
INT cpyone(struct stump *sp,INT paridx,INT upsidx);
INT nmsoup(INT slot);
INT nmsodn(INT slot);
VOID delstump(struct stump *sptr);
VOID delmsp(struct stump *sptr,CHAR *mspnam);
VOID sratob(INT oldref,INT newref);
INT fndstump(CHAR *name);
INT fndidx(struct stump *sp);
struct stump *mchstump(CHAR *name);
INT ydepth(struct stump *stuptr);
INT getmtx(VOID);
INT getmty(VOID);
INT readtree(VOID);
VOID savetree(VOID);
struct stump *stpoff(INT stpnum);
INT rusure(CHAR *dftans);
VOID errwin(INT scn,INT eulx,INT euly,INT elrx,INT elry,INT sulx,INT suly);
GBOOL isfnx(INT c);
GBOOL isfilp(INT c,CHAR *stg);
GBOOL isastg(INT c);
GBOOL isaxstg(INT c);
GBOOL iskeyc(INT c);
INT camidx(GBOOL csmode,GBOOL aamod);
INT getchq(VOID);
VOID toggmode(VOID);
CHAR *mbbkey(CHAR *menuname);
CHAR *pickicon(CHAR *curicon);
VOID appgprept(VOID);
VOID appgprecd(VOID);

INT
main(                              /* main program loop                    */
INT argc,                          /*   number of command-line args        */
CHAR *argv[])                      /*   array of command-line args         */
{
TRY
     INT i,exicode;
     struct stump *sp;
     CHAR *savscn,*hlpscn;

#    ifdef GCWINNT
          if (!canRunUtil()) {
               MessageBox(NULL,NOPROCEED,
                    argv[0],MB_ICONSTOP|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
               return(1);
          }
          if (argc < 2 || !sameas(argv[1],"-wgsrunmt")) {
               MessageBox(NULL,"\n"
                          "WGSMTREE.EXE must not be executed directly.\n"
                          "Use WGSRUNMT to run the Offline Menu Editor.",
                    argv[0],MB_ICONSTOP|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
               return(1);
          }
#    endif // GCWINNT
     filecas=needupc() ? (ALLCAPS+MULTIEX) : (MULTIEX);
     protinit("WGSMTREE ");
#    ifdef GCWINNT
          if (argc == 3) {
               maxstp=atoi(argv[2]);
          }
#    else
          if (argc == 2) {
               maxstp=atoi(argv[1]);
          }
#    endif
     initvid();
     ibdraw(1);
     eospawn();
     workpag=(struct mnupag *)alcmem(sizeof(struct mnupag));
     savepag=(struct mnupag *)alcmem(sizeof(struct mnupag));
     monorcol();
     for (i=0 ; i < NSCNS ; i++) {
          cvtscn(scntbl[i]);
     }
     iniint();
     inilingo();
     avmlst=avlmods(FALSE);
     avmlstaa=(CHAR **)alcmem((nmdfs+2)*sizeof(CHAR *));
     avmlstaa[0]=MMMODN;
     for (i=0 ; i < (nmdfs+1) ; i++) {
          avmlstaa[i+1]=avmlst[i];
     }
     avmlstcs=avlmods(TRUE);
     if (!readtree()) {
          system("."SLS"wgsrbt");
          if (!readtree()) {
               catastro("CAN'T BUILD TREE!");
          }
     }
     mpbb=dfaOpen("wgsmenu2.dat",sizeof(struct mnupag),NULL);
     if ((exicode=setjmp(disaster)) != 0) {
          dfaClose(mpbb);
          finint();
          locate(0,24);
          clsvid();
          exit(exicode);
     }
     mem2scn(scntbl[MAISCN],0,GVIDSCNSIZ);
     tmpscn=alczer(GVIDSCNSIZ);
     locate(14,0);
     setatr(0x70);
     printf("Terminal Mode ");
     drawtree(tiulx,tiuly,tiulx+TWXSIZ-1,tiuly+TWYSIZ-1);
     curx=2;
     curstump=rvtcurs();
     while (!mtdone) {
          locate(curx,cury);
          switch (getchc()) {
          case HOME:
               sp=stpoff(1);
               jmp2txy(sp->tx+1,sp->ty,strlen(sp->name));
               break;
          case END:
               sp=stpoff(1);
               for (i=2 ; i < nstumps ; i++) {
                    if (stpoff(i)->ty > sp->ty) {
                         sp=stpoff(i);
                    }
               }
               jmp2txy(sp->tx+1,sp->ty,strlen(sp->name));
               break;
          case CRSRLF:
               if (stpoff(curstump)->parent) {
                    sp=stpoff(stpoff(curstump)->parent);
                    jmp2txy(sp->tx+1,sp->ty,strlen(sp->name));
               }
               break;
          case CRSRRT:
               if (stpoff(curstump)->child) {
                    sp=stpoff(stpoff(curstump)->child);
                    jmp2txy(sp->tx+1,sp->ty,strlen(sp->name));
               }
               break;
          case CRSRUP:
               if ((sp=nearups()) != NULL) {
                    jmp2txy(sp->tx+1,sp->ty,strlen(sp->name));
               }
               break;
          case CRSRDN:
               if ((sp=neardns()) != NULL) {
                    jmp2txy(sp->tx+1,sp->ty,strlen(sp->name));
               }
               break;
          case F1:
               scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
               iniscn("wgsmth.bin",hlpscn=alcmem(GVIDSCNSIZ));
               explode(hlpscn,6,0,71,23);
               cursiz(GVIDNOCURS);
               getchc();
               cursiz(GVIDLILCURS);
               free(hlpscn);
               mem2scn(savscn,0,GVIDSCNSIZ);
               free(savscn);
               break;
          case F2:
          case '\r':
               editpage();
               if (edtvalc == '\r'
                 && ((sp=neardns()) != NULL || (sp=nearups()) != NULL)) {
                    jmp2txy(sp->tx+1,sp->ty,strlen(sp->name));
               }
               break;
          case F3:
               toggmode();
               break;
          case F4:
               gotopg();
               break;
          case F5:
               addpg();
               break;
          case F6:
               delpg();
               break;
          case F8:
               seapag();
               break;
          case ESC:
          case F10:
               mtdone=1;
               break;
          }
     }
     dfaClose(mpbb);
     savetree();
     finint();
     locate(0,24);
     free(tmpscn);
     clsvid();
     return(0);
EXCEPT
#ifdef GCWINNT
     return(1);
#endif // GCWINNT
}

VOID
editpage(VOID)
{
     CHAR *savscn;
     INT done=0,starts=AGCSTT;

     while (!done) {
          edtvalc=0;
          scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
          if (!dfaAcqEQ(workpag,mbbkey(stpoff(curstump)->name),0)) {
               catastro("MISSING PAGE: %s",stpoff(curstump)->name);
          }
          unpack(workpag);
          movmem(workpag,savepag,sizeof(struct mnupag));
          if (stpoff(curstump)->flags&ISFILE) {
               done=editfile(starts);
          }
          else if (stpoff(curstump)->flags&ISCSMD) {
               done=editcsmod(starts);
          }
          else if (stpoff(curstump)->flags&ISMODU) {
               if (csedit) {
                    done=editcsmod(starts);
               }
               else {
                    done=editmodu(starts);
               }
          }
          else {
               if (workpag->npages == 0) {
                    starts=MDFSTT;
               }
               done=editmenu(starts);
          }
          if (done && (workpag->flags&MDLPAG) && sameas(workpag->modnam,"")) {
               workpag->flags&=~MDLPAG;
               workpag->flags&=~CSMPAG;
               stpoff(curstump)->flags&=~ISMODU;
               stpoff(curstump)->flags&=~ISCSMD;
               updpag();           /* if modpag w/ no modnam (esc hit), mak*/
          }
          mem2scn(savscn,0,GVIDSCNSIZ);
          free(savscn);
          starts=AGCSTT;
     }
     drawtree(tiulx,tiuly,tiulx+TWXSIZ-1,tiuly+TWYSIZ-1);
     curstump=rvtcurs();
}

INT
editfile(
INT edfstt)
{
#define FNPSTT      5              /* file name w/ path state              */
#define DFHSTT      6              /* display file page header? state      */
#define SVFSTT      7              /* save this file page? state           */
     INT upwards=0,modcho;
     CHAR mdfpag[26],agcyon[YONSIZ],dfhyon[YONSIZ],svfyon[YONSIZ];
     CHAR *savscn;

     strcpy(mdfpag,"File Page");
     strcpy(agcyon,((workpag->flags&CNGOTO) ? "Yes" : "No"));
     if (csedit) {
          strcpy(dfhyon,((workpag->flags&NOFPHD) ? "Yes" : "No"));
     }
     else {
          strcpy(dfhyon,((workpag->flags&NOFPHD) ? "No" : "Yes"));
     }
     strcpy(svfyon,"Yes");
     movmem(scntbl[EFMSCN],tmpscn,GVIDSCNSIZ);
     explodeto(tmpscn,1,13,76,24,1,4);
     sstatr(0x2E);
     printfat(1+33,4+1,"%s",workpag->pagnam);
     printfat(1+33,4+2,"%s",mdfpag);
     printfat(1+33,4+3,"%s",agcyon);
     updk4g(1+33,4+4);
     printfat(1+33,4+5,"%s",dfhyon);
     if (csedit) {
          sstatr(0x2F);
          printfat(1+7,4+5,"%s","  Launch File in Windows?");
          sstatr(0x2E);
     }
     printfat(1+2,4+8,"%s",workpag->fname);
     while (1) {
          if (edtvalc == ESC) {
               updpag();
               return(1);
          }
          switch (edfstt) {
          case PGNSTT:
               while (edtval(1+33,4+1,PNMSIZ,workpag->pagnam,istxvc,filecas)) {
                    if (workpag->pagnam[0] == '\0') {
                         printf("\7");
                    }
                    else if (sameas(workpag->pagnam,savepag->pagnam)
                             || !dfaQueryEQ(workpag->menutype,0)) {
                         edfstt=gonstt(PGNSTT,MDFSTT,PGNSTT,MDFSTT);
                         upwards=0;
                         break;
                    }
                    else {
                         errwin(SEASCN,0,6,28,8,26,10);
                    }
                    strcpy(workpag->pagnam,savepag->pagnam);
               }
               break;
          case MDFSTT:
               scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
               if (csedit) {
                    explodeto(scntbl[SEASCN],10,19,39,23,7+31,4+2);
                    explodem=0;
                    explodeto(scntbl[SEASCN],10,20,39,23,7+31,4+2+2);
                    explodem=1;
               }
               else {
                    explodeto(scntbl[SEASCN],10,19,24,23,7+31,4+2);
                    explodem=0;
                    explodeto(scntbl[SEASCN],39,19,39,23,7+31+14,4+2);
                    explodem=1;
               }
               proff(0,0);
               selatr=0x70;
               nslatr=0x3F;
               if ((modcho=choowd((csedit ? csmdfnam : mdfnam),2,
                  7+31+2,4+2+1,7+31+2+10+(csedit ? 15 : 0),
                  4+2+1+(csedit ? 3 : 2),TRUE)) == -ESC) {
                    edtvalc=ESC;
               }
               else {
                    strcpy(mdfpag,csedit ? csmdfnam[modcho] : mdfnam[modcho]);
                    if (modcho != FIPIDX) {
                         workpag->flags&=~FILPAG;
                         stpoff(curstump)->flags&=~ISFILE;
                         workpag->flags|=(modcho == MDPIDX ? MDLPAG : 0);
                         workpag->flags|=(modcho == CSMIDX ? (MDLPAG|CSMPAG) : 0);
                         stpoff(curstump)->flags|=(modcho == MDPIDX ? ISMODU : 0);
                         stpoff(curstump)->flags|=(modcho == CSMIDX ? ISCSMD : 0);
                         workpag->fname[0]='\0';
                         updpag();
                         return(0);
                    }
                    edfstt=(upwards ? PGNSTT : AGCSTT);
               }
               mem2scn(savscn,0,GVIDSCNSIZ);
               free(savscn);
               setatr(0x2E);
               break;
          case AGCSTT:
               if (edtval(1+33,4+3,YONSIZ,agcyon,validyn,MCHOICE+MULTIEX)) {
                    if (agcyon[0] == 'Y') {
                         edfstt=gonstt(MDFSTT,K4GSTT,MDFSTT,K4GSTT);
                         workpag->flags|=CNGOTO;
                    }
                    else {
                         edfstt=gonstt(MDFSTT,DFHSTT,MDFSTT,DFHSTT);
                         workpag->flags&=~CNGOTO;
                    }
                    updk4g(1+33,4+4);
                    upwards=(edfstt == MDFSTT);
               }
               break;
          case K4GSTT:
               if (edtval(1+33,4+4,KEYSIZ,workpag->golock,iskeyc,MULTIEX+ALLCAPS)) {
                    edfstt=gonstt(AGCSTT,DFHSTT,AGCSTT,DFHSTT);
               }
               break;
          case DFHSTT:
               if (edtval(1+33,4+5,YONSIZ,dfhyon,validyn,MCHOICE+MULTIEX)) {
                    if (dfhyon[0] == 'Y') {
                         if (csedit) {
                              workpag->flags|=NOFPHD;
                         }
                         else {
                              workpag->flags&=~NOFPHD;
                         }
                    }
                    else {
                         if (csedit) {
                              workpag->flags&=~NOFPHD;
                         }
                         else {
                              workpag->flags|=NOFPHD;
                         }
                    }
                    edfstt=gonstt((workpag->flags&CNGOTO) ? K4GSTT : AGCSTT,
                           FNPSTT,(workpag->flags&CNGOTO) ? K4GSTT : AGCSTT,
                           FNPSTT);
               }
               break;
       case FNPSTT:
               while (edtval(1+2,4+8,71,workpag->fname,isfilp,filecas)) {
                    if (workpag->fname[0] != '\0') {
                         edfstt=gonstt(DFHSTT,SVFSTT,DFHSTT,SVFSTT);
                         break;
                    }
                    printf("\7");
               }
               break;
          case SVFSTT:
               if (edtval(1+33,4+10,YONSIZ,svfyon,validyn,MCHOICE+MULTIEX)) {
                    if (edtvalc == '\r' && svfyon[0] == 'Y') {
                         updpag();
                         return(1);
                    }
                    edfstt=gonstt(FNPSTT,SVFSTT,FNPSTT,SVFSTT);
               }
               break;
          }
     }
}

INT
editmodu(INT eddstt)
{
#define MDNSTT      5              /* name of module state                 */
#define DMHSTT      6              /* display module header? state         */
#define MCSSTT      7              /* command string on entry to modu      */
#define SVDSTT      8              /* save this module page? state         */
     INT modcho,upwards=0;
     CHAR mdfpag[12],agcyon[YONSIZ],dmhyon[YONSIZ],svdyon[YONSIZ];
     CHAR *savscn;

     strcpy(mdfpag,"Module Page");
     strcpy(agcyon,((workpag->flags&CNGOTO) ? "Yes" : "No"));
     strcpy(dmhyon,((workpag->flags&NOMPHD) ? "No" : "Yes"));
     strcpy(svdyon,"Yes");
     explodeto(scntbl[EFMSCN],1,0,63,12,7,4);
     sstatr(0x2E);
     printfat(7+33,4+1,"%s",workpag->pagnam);
     printfat(7+33,4+2,"%s",mdfpag);
     printfat(7+33,4+3,"%s",agcyon);
     updk4g(7+33,4+4);
     printfat(7+33,4+5,"%s",workpag->modnam);
     printfat(7+33,4+6,"%s",dmhyon);
     printfat(7+2,4+9,"%s",workpag->cmdstg);
     while (1) {
          if (edtvalc == ESC) {
               updpag();
               return(1);
          }
          switch (eddstt) {
          case PGNSTT:
               while (edtval(7+33,4+1,PNMSIZ,workpag->pagnam,istxvc,filecas)) {
                    if (workpag->pagnam[0] == '\0') {
                         printf("\7");
                    }
                    else if (sameas(workpag->pagnam,savepag->pagnam)
                             || !dfaQueryEQ(workpag->menutype,0)) {
                         eddstt=gonstt(PGNSTT,MDFSTT,PGNSTT,MDFSTT);
                         upwards=0;
                         break;
                    }
                    else {
                         errwin(SEASCN,0,6,28,8,26,10);
                    }
                    strcpy(workpag->pagnam,savepag->pagnam);
               }
               break;
          case MDFSTT:
               scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
               explodeto(scntbl[SEASCN],10,19,24,23,7+31+5,4+2);
               explodem=0;
               explodeto(scntbl[SEASCN],39,19,39,23,7+31+14+5,4+2);
               explodem=1;
               proff(0,0);
               selatr=0x70;
               nslatr=0x3F;
               if ((modcho=choowd(mdfnam,1,7+36+2,4+2+1,7+36+2+10,4+2+1+2,TRUE)) == -ESC) {
                    edtvalc=ESC;
               }
               else {
                    strcpy(mdfpag,mdfnam[modcho]);
                    if (modcho != MDPIDX) {
                         workpag->flags&=~MDLPAG;
                         stpoff(curstump)->flags&=~ISMODU;
                         workpag->flags|=(modcho == FIPIDX ? FILPAG : 0);
                         stpoff(curstump)->flags|=(modcho == FIPIDX ? ISFILE : 0);
                         if (workpag->modnam[0] != '\0') {
                              decref(workpag->modnam);
                         }
                         workpag->modnam[0]='\0';
                         workpag->cmdstg[0]='\0';
                         updpag();
                         return(0);
                    }
                    eddstt=(upwards ? PGNSTT : AGCSTT);
               }
               mem2scn(savscn,0,GVIDSCNSIZ);
               free(savscn);
               setatr(0x2E);
               break;
          case AGCSTT:
               if (edtval(7+33,4+3,YONSIZ,agcyon,validyn,MCHOICE+MULTIEX)) {
                    if (agcyon[0] == 'Y') {
                         eddstt=gonstt(MDFSTT,K4GSTT,MDFSTT,K4GSTT);
                         workpag->flags|=CNGOTO;
                    }
                    else {
                         eddstt=gonstt(MDFSTT,MDNSTT,MDFSTT,MDNSTT);
                         workpag->flags&=~CNGOTO;
                    }
                    updk4g(7+33,4+4);
                    upwards=(eddstt == MDFSTT);
               }
               break;
          case K4GSTT:
               if (edtval(7+33,4+4,KEYSIZ,workpag->golock,iskeyc,MULTIEX+ALLCAPS)) {
                    eddstt=gonstt(AGCSTT,MDNSTT,AGCSTT,MDNSTT);
                    upwards=(eddstt != MDNSTT);
               }
               break;
          case MDNSTT:
               scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
               explodeto(scntbl[MESSCN],48,12,73,24,41,6);
               if (workpag->modnam[0] != '\0') {
                    decref(workpag->modnam);
               }
               proff(0,0);
               selatr=0x70;
               nslatr=0x3F;
               if (avmlst[0] == NULL) {
                    catastro("No modules available!");
               }
               modcho=choowd(avmlst,camidx(FALSE,FALSE),41+1,6+1,41+24,6+11,
                            (workpag->modnam[0] == '\0' ? FALSE : TRUE));
               if (modcho >= 0) {
                    strcpy(workpag->modnam,avmlst[modcho]);
               }
               incref(workpag->modnam);
               eddstt=(upwards ? ((workpag->flags&CNGOTO) ? K4GSTT : AGCSTT) : DMHSTT);
               mem2scn(savscn,0,GVIDSCNSIZ);
               free(savscn);
               setatr(0x2E);
               printfat(7+33,4+5,"%-24s",workpag->modnam);
               break;
          case DMHSTT:
               if (edtval(7+33,4+6,YONSIZ,dmhyon,validyn,MCHOICE+MULTIEX)) {
                    if (dmhyon[0] == 'Y') {
                         workpag->flags&=~NOMPHD;
                    }
                    else {
                         workpag->flags|=NOMPHD;
                    }
                    eddstt=gonstt(MDNSTT,MCSSTT,MDNSTT,MCSSTT);
                    upwards=(eddstt == MDNSTT);
               }
               break;
          case MCSSTT:
               if (edtval(7+2,4+9,CMDSIZ,workpag->cmdstg,isastg,MULTIEX)) {
                    eddstt=gonstt(DMHSTT,SVDSTT,DMHSTT,SVDSTT);
               }
               break;
          case SVDSTT:
               if (edtval(7+33,4+11,YONSIZ,svdyon,validyn,MCHOICE+MULTIEX)) {
                    if (edtvalc == '\r' && svdyon[0] == 'Y') {
                         updpag();
                         return(1);
                    }
                    eddstt=gonstt(MCSSTT,SVDSTT,MCSSTT,SVDSTT);
               }
               break;
          }
     }
}

INT
editcsmod(
INT eddstt)
{
     INT modcho,upwards=0,savcho;
     CHAR mdfpag[26],agcyon[YONSIZ],dmhyon[YONSIZ],svdyon[YONSIZ];
     CHAR *savscn;

     sprintf(mdfpag,"%s Module Page",(workpag->flags&CSMPAG) ? "C/S-mode" :
          "Terminal-mode");
     strcpy(agcyon,((workpag->flags&CNGOTO) ? "Yes" : "No"));
     strcpy(dmhyon,((workpag->flags&NOMPHD) ? "No" : "Yes"));
     strcpy(svdyon,"Yes");
     movmem(scntbl[EFMSCN],tmpscn,GVIDSCNSIZ);
     movmem(&scntbl[EFMSCN][7*160],&tmpscn[6*160],GVIDSCNSIZ-(7*160));
     explodeto(tmpscn,1,0,63,11,7,4);
     sstatr(0x2E);
     printfat(7+33,4+1,"%s",workpag->pagnam);
     printfat(7+33,4+2,"%s",mdfpag);
     printfat(7+33,4+3,"%s",agcyon);
     updk4g(7+33,4+4);
     printfat(7+33,4+5,"%s",workpag->modnam);
     savcho=(workpag->flags&CSMPAG) ? CSMIDX : MDPIDX;
     printfat(7+2,4+8,"%s",workpag->cmdstg);
     while (1) {
          if (edtvalc == ESC) {
               updpag();
               return(1);
          }
          switch (eddstt) {
          case PGNSTT:
               while (edtval(7+33,4+1,PNMSIZ,workpag->pagnam,istxvc,filecas)) {
                    if (workpag->pagnam[0] == '\0') {
                         printf("\7");
                    }
                    else if (sameas(workpag->pagnam,savepag->pagnam)
                             || !dfaQueryEQ(workpag->menutype,0)) {
                         eddstt=gonstt(PGNSTT,MDFSTT,PGNSTT,MDFSTT);
                         upwards=0;
                         break;
                    }
                    else {
                         errwin(SEASCN,0,6,28,8,26,10);
                    }
                    strcpy(workpag->pagnam,savepag->pagnam);
               }
               break;
          case MDFSTT:
               scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
               explodeto(scntbl[SEASCN],10,19,39,23,7+31+5,4+2);
               explodem=0;
               explodeto(scntbl[SEASCN],10,20,39,23,7+31+5,4+2+2);
               explodem=1;
               proff(0,0);
               selatr=0x70;
               nslatr=0x3F;
               if ((modcho=choowd(csmdfnam,(workpag->flags&CSMPAG) ? CSMIDX :
                      MDPIDX,7+36+2,4+2+1,7+36+2+10+
                      (csedit ? 15 : 0),4+2+1+3,TRUE)) == -ESC) {
                    edtvalc=ESC;
               }
               else {
                    strcpy(mdfpag,csmdfnam[modcho]);
                    if (modcho != savcho) {
                         workpag->flags&=~CSMPAG;
                         workpag->flags&=~MDLPAG;
                         stpoff(curstump)->flags&=~ISCSMD;
                         stpoff(curstump)->flags&=~ISMODU;
                         workpag->flags|=(modcho == MDPIDX ? MDLPAG : 0);
                         workpag->flags|=(modcho == CSMIDX ? (MDLPAG|CSMPAG) : 0);
                         workpag->flags|=(modcho == FIPIDX ? FILPAG : 0);
                         stpoff(curstump)->flags|=(modcho == MDPIDX ? ISMODU : 0);
                         stpoff(curstump)->flags|=(modcho == CSMIDX ? ISCSMD : 0);
                         stpoff(curstump)->flags|=(modcho == FIPIDX ? ISFILE : 0);
                         if (workpag->modnam[0] != '\0') {
                              decref(workpag->modnam);
                              workpag->modnam[0]='\0';
                              workpag->cmdstg[0]='\0';
                         }
                         updpag();
                         free(savscn);
                         return(0);
                    }
                    eddstt=(upwards ? PGNSTT : AGCSTT);
               }
               mem2scn(savscn,0,GVIDSCNSIZ);
               free(savscn);
               setatr(0x2E);
               break;
          case AGCSTT:
               if (edtval(7+33,4+3,YONSIZ,agcyon,validyn,MCHOICE+MULTIEX)) {
                    if (agcyon[0] == 'Y') {
                         eddstt=gonstt(MDFSTT,K4GSTT,MDFSTT,K4GSTT);
                         workpag->flags|=CNGOTO;
                    }
                    else {
                         eddstt=gonstt(MDFSTT,MDNSTT,MDFSTT,MDNSTT);
                         workpag->flags&=~CNGOTO;
                    }
                    updk4g(7+33,4+4);
                    upwards=(eddstt == MDFSTT);
               }
               break;
          case K4GSTT:
               if (edtval(7+33,4+4,KEYSIZ,workpag->golock,iskeyc,MULTIEX+ALLCAPS)) {
                    eddstt=gonstt(AGCSTT,MDNSTT,AGCSTT,MDNSTT);
                    upwards=(eddstt != MDNSTT);
               }
               break;
          case MDNSTT:
               scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
               explodeto(scntbl[MESSCN],48,12,73,24,41,6);
               if (workpag->modnam[0] != '\0') {
                    decref(workpag->modnam);
               }
               proff(0,0);
               setatr(0x70);
               printfat(43,6," Select a%s Module ",
                            (workpag->flags&CSMPAG) ? " C/S" : "");
               selatr=0x70;
               nslatr=0x3F;
               if (((workpag->flags&CSMPAG) ? avmlstcs : avmlst)[0] == NULL) {
                    catastro("No %s mode modules available!",
                       (workpag->flags&CSMPAG)
                           ? "client/server" : "terminal");
               }
               modcho=choowd((workpag->flags&CSMPAG) ? avmlstcs : avmlstaa,
                  camidx(workpag->flags&CSMPAG,TRUE),41+1,6+1,41+24,6+11,
                  (workpag->modnam[0] == '\0' ? FALSE : TRUE));
               if (modcho >= 0) {
                    if (workpag->flags&CSMPAG) {
                         strcpy(workpag->modnam,avmlstcs[modcho]);
                    }
                    else {
                         strcpy(workpag->modnam,avmlstaa[modcho]);
                    }
               }
               incref(workpag->modnam);
               eddstt=(upwards ? ((workpag->flags&CNGOTO) ? K4GSTT : AGCSTT)
                 : MCSSTT);
               mem2scn(savscn,0,GVIDSCNSIZ);
               free(savscn);
               setatr(0x2E);
               printfat(7+33,4+5,"%-24s",workpag->modnam);
               break;
          case MCSSTT:
               if (edtval(7+2,4+8,CMDSIZ,workpag->cmdstg,isastg,MULTIEX)) {
                    eddstt=gonstt(MDNSTT,SVDSTT,MDNSTT,SVDSTT);
                    upwards=(eddstt == MDNSTT);
               }
               break;
          case SVDSTT:
               if (edtval(7+33,4+10,YONSIZ,svdyon,validyn,MCHOICE+MULTIEX)) {
                    if (edtvalc == '\r' && svdyon[0] == 'Y') {
                         updpag();
                         return(1);
                    }
                    eddstt=gonstt(MCSSTT,SVDSTT,MCSSTT,SVDSTT);
               }
               break;
          }
     }
}

INT
editmenu(INT edmstt)
{
#define MAMSTT      5              /* make auto-menu? state                */
#define EMLSTT      6              /* edit menu looks state                */
#define EMTSTT      7              /* edit a menu title state              */
#define ESCSTT      8              /* edit a select character state        */
#define ESDSTT      9              /* edit a short description state       */
#define SVMSTT     10              /* save menu changes? state             */

     INT upwards=0,modcho;
     CHAR mdfpag[26],slcbuf[2]={"\0\0"};
     CHAR agcyon[YONSIZ],mamyon[YONSIZ],etwyon[YONSIZ],svmyon[YONSIZ];
     CHAR mnuttl[TITLSZ];
     CHAR *savscn;

     msoidx=edtvalc=0;
     strcpy(mdfpag,"Menu Page");
     strcpy(agcyon,((workpag->flags&CNGOTO) ? "Yes" : "No"));
     strcpy(mamyon,((workpag->flags&AUTPAG) ? "Yes" : "No"));
     strcpy(etwyon,csedit && (workpag->flags&DFTDSP) ? "Yes" : "No");
     strcpy(mnuttl,((workpag->flags&AUTPAG) ? "\0" : workpag->mnuttl));
     strcpy(svmyon,"Yes");
     explodeto(scntbl[csedit ? CSMSCN : EMNSCN],1,0,77,23,1,0+1);
     rmsobx();
     sstatr(curstump == 1 ? 0x2A : 0x2E);
     if (curstump == 1) {
          printfat(23,1+1,"%s","Page Name:");
          printfat(3,2+1,"%s","Use as a Menu, Module or File?");
     }
     printfat(34,1+1,"%s",workpag->pagnam);
     printfat(34,2+1,"%s",mdfpag);
     sstatr(0x2E);
     printfat(34,3+1,"%s",agcyon);
     updk4g(34,4+1);
     printfat(34,5+1,"%s",mamyon);
     printfat(34,7+1,"%s",mnuttl);
     uemlttl(etwyon,mnuttl);
     rdomso();
     while (1) {
          if (edtvalc == ESC) {
               updpag();
               return(1);
          }
          switch (edmstt) {
          case PGNSTT:
               while (edtval(34,1+1,PNMSIZ,workpag->pagnam,istxvc,filecas)) {
                    if (workpag->pagnam[0] == '\0') {
                         printf("\7");
                    }
                    else if (sameas(workpag->pagnam,savepag->pagnam)
                             || !dfaQueryEQ(workpag->menutype,0)) {
                         edmstt=gonstt(PGNSTT,MDFSTT,PGNSTT,MDFSTT);
                         upwards=0;
                         break;
                    }
                    else {
                         errwin(SEASCN,0,6,28,8,26,10);
                    }
                    strcpy(workpag->pagnam,savepag->pagnam);
               }
               break;
          case MDFSTT:
               if (sameas(workpag->pagnam,"TOP")) {
                    edmstt=AGCSTT;
                    break;
               }
               scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
               if (csedit) {
                    explodeto(scntbl[SEASCN],10,19,39,23,7+31-1,4+2-3);
                    explodem=0;
                    explodeto(scntbl[SEASCN],10,20,39,23,7+31-1,4+2-3+2);
                    explodem=1;
               }
               else {
                    explodeto(scntbl[SEASCN],10,19,24,23,7+31-1,4+2-3);
                    explodem=0;
                    explodeto(scntbl[SEASCN],39,19,39,23,7+31+14-1,4+2-3);
                    explodem=1;
               }
               proff(0,0);
               selatr=0x70;
               nslatr=0x3F;
               if ((modcho=choowd((csedit ? csmdfnam : mdfnam),0,
                  7+30+2,2+1+1,7+30+2+10+(csedit ? 15 : 0),
                  2+1+(csedit ? 3 : 2)+1,TRUE)) == -ESC) {
                    edtvalc=ESC;
               }
               else {
                    strcpy(mdfpag,csedit ? csmdfnam[modcho] : mdfnam[modcho]);
                    if (modcho != MNPIDX) {
                         workpag->flags&=~AUTPAG;
                         stpoff(curstump)->flags&=~ISAUTO;
                         workpag->flags|=(modcho == MDPIDX ? MDLPAG : 0);
                         workpag->flags|=(modcho == CSMIDX ? (MDLPAG|CSMPAG) : 0);
                         workpag->flags|=(modcho == FIPIDX ? FILPAG : 0);
                         stpoff(curstump)->flags|=(modcho == MDPIDX ? ISMODU : 0);
                         stpoff(curstump)->flags|=(modcho == CSMIDX ? ISCSMD : 0);
                         stpoff(curstump)->flags|=(modcho == FIPIDX ? ISFILE : 0);
                         orphan(stpoff(curstump));
                         workpag->fname[0]='\0';
                         workpag->npages=0;
                         setmem(workpag->page,MAXSEL*sizeof(struct pglink),0);
                         updpag();
                         free(savscn);
                         return(0);
                    }
                    edmstt=(upwards ? PGNSTT : AGCSTT);
               }
               mem2scn(savscn,0,GVIDSCNSIZ);
               free(savscn);
               setatr(0x2E);
               break;
          case AGCSTT:
               if (edtval(34,3+1,YONSIZ,agcyon,validyn,MCHOICE+MULTIEX)) {
                    if (agcyon[0] == 'Y') {
                         edmstt=gonstt(MDFSTT,K4GSTT,MDFSTT,K4GSTT);
                         workpag->flags|=CNGOTO;
                    }
                    else {
                         edmstt=gonstt(MDFSTT,MAMSTT,MDFSTT,MAMSTT);
                         workpag->flags&=~CNGOTO;
                    }
                    updk4g(34,4+1);
                    upwards=(edmstt == MDFSTT);
               }
               break;
          case K4GSTT:
               if (edtval(34,4+1,KEYSIZ,workpag->golock,iskeyc,MULTIEX+ALLCAPS)) {
                    edmstt=gonstt(AGCSTT,MAMSTT,AGCSTT,MAMSTT);
               }
               break;
          case MAMSTT:
               if (edtval(34,5+1,YONSIZ,mamyon,validyn,MCHOICE+MULTIEX)) {
                    if (mamyon[0] == 'Y') {
                         edmstt=gonstt((workpag->flags&CNGOTO) ? K4GSTT
                           : AGCSTT,ESCSTT,
                           (workpag->flags&CNGOTO) ? K4GSTT
                           : AGCSTT,ESCSTT);
                         workpag->flags|=AUTPAG;
                         stpoff(curstump)->flags|=ISAUTO;
                    }
                    else {
                         edmstt=gonstt((workpag->flags&CNGOTO) ? K4GSTT :
                           AGCSTT,EMLSTT,(workpag->flags&CNGOTO)
                           ? K4GSTT : AGCSTT,EMLSTT);
                         workpag->flags&=~AUTPAG;
                         stpoff(curstump)->flags&=~ISAUTO;
                    }
                    if (edmstt == ESCSTT) {
                         amsobx();
                    }
                    uemlttl(etwyon,mnuttl);
               }
               break;
          case EMLSTT:
                if (edtval(34,6+1,YONSIZ,etwyon,validyn,MULTIEX+MCHOICE)) {
                    if (csedit) {
                         if (!(workpag->flags&AUTPAG)) {
                              if (etwyon[0] == 'Y') {
                                   workpag->flags|=DFTDSP;
                              }
                              else {
                                   workpag->flags&=~DFTDSP;
                              }
                         }
                         uemlttl(etwyon,mnuttl);
                    }
                    else if (edtvalc == '\r' && etwyon[0] == 'Y') {
                         mdintf();
                         uemlttl(etwyon,mnuttl);
                    }
                    edmstt=gonstt(MAMSTT,EMTSTT,MAMSTT,EMTSTT);
               }
               break;
          case EMTSTT:
               uemlttl(etwyon,mnuttl);
               if (edtval(34,7+1,TITLSZ,mnuttl,valttl,MULTIEX)) {
                    uemlttl(etwyon,mnuttl);
                    strcpy(workpag->mnuttl,mnuttl);
                    edmstt=((workpag->flags&AUTPAG)
                            ? gonstt(MAMSTT,ESCSTT,MAMSTT,ESCSTT)
                            : gonstt(EMLSTT,ESCSTT,EMLSTT,ESCSTT));
                    if (edmstt == ESCSTT) {
                         amsobx();
                    }
               }
               break;
          case ESCSTT:
               if (csedit) {
                    edmstt=ESDSTT;
                    break;
               }
               slcbuf[0]=workpag->page[msoidx].selchr;
               if (edtval(scx(),msy(),2,slcbuf,valesc,filecas)) {
                    if (slcbuf[0] != workpag->page[msoidx].selchr
                        && !xistsc(slcbuf[0]) && !csedit) {
                         workpag->page[msoidx].selchr=slcbuf[0];
                    }
                    edmstt=gonmso(edmstt);
               }
               break;
          case ESDSTT:
               if (edtval(sdx(),msy(),SHDSIZ,workpag->page[msoidx].shortd,
                 valesd,MULTIEX)) {
                    edmstt=gonmso(edmstt);
               }
               break;
          case SVMSTT:
               if (edtval(67,22+1,YONSIZ,svmyon,validyn,MCHOICE+MULTIEX)) {
                    if (edtvalc == '\r' && svmyon[0] == 'Y') {
                         updpag();
                         return(1);
                    }
                    edmstt=gonstt(ESCSTT,SVMSTT,ESCSTT,SVMSTT);
                    if (edmstt == ESCSTT) {
                         amsobx();
                    }
               }
               break;
          }
     }
}

VOID
updpag(VOID)
{
     if (!sameas(workpag->pagnam,savepag->pagnam)) {
          renparto(workpag->pagnam,curstump);
          if (stpoff(curstump)->child) {
               dxystu(stpoff(stpoff(curstump)->child),
                strlen(workpag->pagnam)-strlen(savepag->pagnam),0);
          }
          strcpy(stpoff(curstump)->name,workpag->pagnam);
          cpmsonam();
     }
     if (!dfaAcqEQ(NULL,savepag->menutype,0)) {
          catastro("LOST MENU PAGE!");
     }
     savepage(workpag,FALSE);
}

GBOOL
valesc(
INT c,
CHAR *stg)
{
     stg[1]='\0';
     switch (c) {
     case ALT_E:
          editmso(0);
          break;
     case ALT_M:
          movemso();
          break;
     case ALT_D:
          delmso();
          break;
     default:
          if (workpag->page[msoidx].destpage[0] == '\0') {
               editmso(0);
               break;
          }
          if (isselc(c)) {
               stg[0]=toupper(c);
          }
          return(FALSE);
     }
     edtvalc='\r';
     stg[0]=workpag->page[msoidx].selchr;
     return(FALSE);
}

GBOOL
valesd(
INT c,
CHAR *stg)
{
     switch (c) {
     case ALT_E:
          editmso(0);
          break;
     case ALT_M:
          movemso();
          break;
     case ALT_D:
          delmso();
          break;
     default:
          if (workpag->page[msoidx].destpage[0] == '\0') {
               if (!isastg(c)) {
                    c='\0';
               }
               editmso((CHAR)c);
               strcpy(stg,workpag->page[msoidx].shortd);
               break;
          }
          return(isastg(c));
     }
     edtvalc='\r';
     return(FALSE);
}

GBOOL
valttl(
INT c,
CHAR *stg)
{
     (VOID)stg;
     return((c >= ' ') ? TRUE : FALSE);
}

VOID
editmso(CHAR dstart)
{
#define EMCSTT      0              /* edit menu option: selchar/icon state */
#define EMDSTT      1              /* edit menu option: short desc state   */
#define EMKSTT      2              /* edit menu option: key req state      */
#define EMOSTT      3              /* edit menu option: display opt state  */
#define EMPSTT      4              /* edit menu option: dest page state    */
#define EMSSTT      5              /* edit menu option: save this state    */
#define EMLSTT      6              /* edit menu option: long desc state    */

#define SAMEDP      0              /* same destination page as before      */
#define MAKEDP      1              /* make this new destination page       */
#define MOVEDP      2              /* move this destination page here      */
#define COPYDP      3              /* copy & rename this destination page  */
     CHAR *savscn,*sv2scn,opage[PNMSIZ]="",*sp;
     INT eemstt,emodun=0,dwdpag=0,dopcho=0,upwards=0,sn,upsib,i;
     CHAR selchr[2]={"\0\0"},iconame[FNEXSZ],shortd[SHDSIZ],longd[LNDSIZ],
          keyreq[KEYSIZ],optdsp[12],dpage[PNMSIZ],yesans[YONSIZ],
          icostt[FNSIZE];
     CHAR *opdstg[4]={
          "Hide option","Dim option ","Show option",NULL
     };
     CHAR *opdstgcs[3]={
          "Hide option","Show option",NULL
     };
     struct stump *cpyptr;
     CHAR *z[3]={"     Selection name",
                 "        Description",
                 "     Icon file name"};

     updpag();
     movmem(workpag,savepag,sizeof(struct mnupag));
     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     movmem(scntbl[MESSCN],tmpscn,GVIDSCNSIZ);
     if (csedit) {
          movmem(&scntbl[MESSCN][2*160],&tmpscn[3*160],GVIDSCNSIZ-3*160);
          for (i=0 ; i < 9 ; i++) {
               movmem(&tmpscn[i*160+68],&tmpscn[i*160+106],40);
          }
          for (i=1 ; i < 20 ; i++) {
               tmpscn[1*160+2*i]=z[0][i-1];
               tmpscn[2*160+2*i]=z[1][i-1];
               tmpscn[3*160+2*i]=z[2][i-1];
          }
     }
     explodeto(tmpscn,0,0,csedit ? 72 : 53,csedit ? 8 : 7,csedit ? 3 : 14,8);
     strcpy(yesans,"Yes");
     sstatr(0x6E);
     eemstt=csedit ? EMDSTT : EMCSTT;
     if (!csedit && workpag->page[msoidx].destpage[0] == '\0') {
          selchr[0]=shortd[0]=keyreq[0]=dpage[0]='\0';
          strcpy(optdsp,opdstg[1]);
          if (isalnum(edtvalc&0xFF) && !xistsc(edtvalc)) {
               eemstt=EMDSTT;
               printfat(14+22,8+1,"%c",selchr[0]=toupper(edtvalc));
          }
     }
     else {
          if (csedit) {
               selchr[0]='C';
               strcpy(iconame,workpag->page[msoidx].iconame);
               stzcpy(icostt,workpag->page[msoidx].iconame,FNSIZE);
               if (workpag->flags&DFTDSP) {
                    if (iconame[0] != '\0') {
                         printfat(3+22,8+3,"%s.ico",iconame);
                    }
               }
               else {
                    printfat(3+22,8+3,"N/A");
               }
          }
          else {
               selchr[0]=workpag->page[msoidx].selchr;
               printfat(14+22,8+1,"%c",selchr[0]);
          }
          strcpy(shortd,dstart == '\0' ? workpag->page[msoidx].shortd :
           spr("%c",dstart));
          printfat(csedit ? 3+22 : 14+22,csedit ? 8+1 : 8+2,"%s",shortd);
          if (csedit) {
               strcpy(longd,workpag->page[msoidx].longd);
               printfat(3+22,8+2,"%s",longd);
          }
          strcpy(keyreq,workpag->page[msoidx].keyreq);
          printfat(csedit ? 3+22 : 14+22,csedit ? 8+4 : 8+3,"%s",keyreq);
          if (csedit) {
               strcpy(optdsp,opdstgcs[workpag->page[msoidx].optdsp == 0 ? 0 : 1]);
          }
          else {
               strcpy(optdsp,opdstg[(SHORT)workpag->page[msoidx].optdsp]);
          }
          printfat(csedit ? 3+22 : 14+22,csedit ? 8+5 : 8+4,"%s",optdsp);
          dopcho=(optdsp[0] == 'H' ? 0 : (csedit || optdsp[0] == 'D' ? 1 : 2));
          strcpy(dpage,workpag->page[msoidx].destpage);
          strcpy(opage,workpag->page[msoidx].destpage);
          printfat(csedit ? 3+22 : 14+22,csedit ? 8+6 : 8+5,"%s",dpage);
          printfat(csedit ? 3+22 : 14+22,csedit ? 8+7 : 8+6,"%s",yesans);
     }
     while (!emodun) {
          if (edtvalc == ESC) {
               break;
          }
          switch (eemstt) {
          case EMCSTT:
               if (csedit) {
                    if (!(workpag->flags&DFTDSP)) {
                         eemstt=EMKSTT;
                    }
                    else {
                         sp=pickicon(iconame);
                         if (sameas(sp,"*")) {
                              edtvalc=ESC;
                         }
                         else {
                              stzcpy(iconame,sp,FNEXSZ);
                              if ((sp=strchr(iconame,'.')) != NULL) {
                                   *sp='\0';
                              }
                              sstatr(0x6E);
                              printfat(3+22,8+3,spr("%-12.12s","%s.ico"),iconame);
                              eemstt=gonstt(EMLSTT,EMKSTT,EMLSTT,EMKSTT);
                         }
                    }
               }
               else while (edtval(14+22,8+1,sizeof(selchr),selchr,isvslc,filecas)) {
                    if (!xistsc(selchr[0])) {
                         if (selchr[0] != '\0') {
                              eemstt=gonstt(EMCSTT,EMDSTT,EMCSTT,EMDSTT);
                              break;
                         }
                         printf("\7");
                    }
                    else {
                         errwin(SEASCN,28,9,70,12,20,9);
                    }
               }
               break;
          case EMDSTT:
               while (edtval(csedit ? 3+22 : 14+22,csedit ? 8+1 : 8+2,SHDSIZ,
                    shortd,isaxstg,MULTIEX)) {
                    if (shortd[0] != '\0') {
                         eemstt=gonstt(EMDSTT,csedit ? EMLSTT : EMKSTT,
                                       EMDSTT,csedit ? EMLSTT : EMKSTT);
                         break;
                    }
                    printf("\7");
               }
               break;
          case EMLSTT:
               if (edtval(3+22,8+2,LNDSIZ,longd,isaxstg,MULTIEX)) {
                    eemstt=gonstt(EMDSTT,EMCSTT,EMDSTT,EMCSTT);
               }
               break;
          case EMKSTT:
               if (edtval(csedit ? 3+22 : 14+22,csedit ? 8+4 : 8+3,KEYSIZ,
                 keyreq,iskeyc,MULTIEX+ALLCAPS)) {
                    upwards=(workpag->flags&DFTDSP) ? EMCSTT : EMLSTT;
                    if (keyreq[0] == '\0' || (workpag->flags&AUTPAG)) {
                         eemstt=gonstt(csedit ? upwards : EMDSTT,EMPSTT,
                                       csedit ? upwards : EMDSTT,EMPSTT);
                    }
                    else {
                         eemstt=gonstt(csedit ? upwards : EMDSTT,EMOSTT,
                                       csedit ? upwards : EMDSTT,EMOSTT);
                    }
                    upwards=0;
               }
               break;
          case EMOSTT:
               scn2mem(sv2scn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
               movmem(scntbl[SEASCN],tmpscn,GVIDSCNSIZ);
               for (i=0 ; i < 5 ; i++) {
                    movmem(&scntbl[SEASCN][((i+19)*80+8)*2],
                           &tmpscn[((i+19)*80+23)*2],(24-9)*2);
               }
               if (csedit) {
                    movmem(&tmpscn[23*160],
                           &tmpscn[22*160],GVIDSCNSIZ-23*160);
               }
               explodeto(tmpscn,25,19,39,csedit ? 22 : 23,7+30,9);
               proff(0,0);
               selatr=0x70;
               nslatr=0x3F;
               if ((dopcho=choowd(csedit ? opdstgcs : opdstg,dopcho,
                  7+30+2,1+9,7+30+2+10,1+9+(csedit ? 1 : 2),TRUE)) == -ESC) {
                    edtvalc=ESC;
               }
               else {
                    strcpy(optdsp,csedit ? opdstgcs[dopcho] : opdstg[dopcho]);
                    eemstt=(upwards ? EMKSTT : EMPSTT);
               }
               mem2scn(sv2scn,0,GVIDSCNSIZ);
               free(sv2scn);
               sstatr(0x6E);
               printfat(csedit ? 3+22 : 14+22,csedit ? 8+5 : 8+4,"%s",optdsp);
               break;
          case EMPSTT:
               while (edtval(csedit ? 3+22 : 14+22,csedit ? 8+6 : 8+5,PNMSIZ,
                    dpage,istxvc,MULTIEX+ALLCAPS)) {
                    if (dpage[0] != '\0') {
                         if ((sn=fndstump(dpage)) != 0 && !sameas(opage,dpage)) {
                              if (!sameas(stpoff(sn)->name,"TOP")
                                  && stpoff(sn)->parent == 0) {
                                   if ((dwdpag=mcnpag()) == 0) {
                                        continue;
                                   }
                              }
                              else {
                                   if ((dwdpag=crnpag()) == 0) {
                                        continue;
                                   }
                              }
                         }
                         else {
                              dwdpag=(sameas(opage,dpage) ? SAMEDP : MAKEDP);
                         }
                         upwards=1;
                         if (keyreq[0] == '\0' || (workpag->flags&AUTPAG)) {
                              eemstt=gonstt(EMKSTT,EMSSTT,EMKSTT,EMSSTT);
                         }
                         else {
                              eemstt=gonstt(EMOSTT,EMSSTT,EMOSTT,EMSSTT);
                         }
                         break;
                    }
                    printf("\7");
               }
               break;
          case EMSSTT:
               if (edtval(csedit ? 3+22 : 14+22,csedit ? 8+7 : 8+6,YONSIZ,
                 yesans,validyn,MULTIEX+MCHOICE)) {
                    if (edtvalc == '\r') {
                         if (yesans[0] == 'Y') {
                              workpag->page[msoidx].selchr=selchr[0];
                              if ((sp=strchr(iconame,'.')) != NULL) {
                                   *sp='\0';
                              }
                              stzcpy(workpag->page[msoidx].iconame,
                                                           iconame,FNSIZE);
                              if (csedit && !sameas(iconame,icostt)) {
                                   workpag->ichange=time(NULL);
                              }
                              strcpy(workpag->page[msoidx].shortd,shortd);
                              strcpy(workpag->page[msoidx].longd,longd);
                              strcpy(workpag->page[msoidx].keyreq,keyreq);
                              switch (optdsp[0]) {
                              case 'H':
                                   workpag->page[msoidx].optdsp=0;
                                   break;
                              case 'D':
                                   workpag->page[msoidx].optdsp=1;
                                   break;
                              case 'S':
                                   workpag->page[msoidx].optdsp=2;
                                   break;
                              }
                              if (opage[0] != '\0' && dwdpag != SAMEDP) {
                                   losedp(stpoff(fndstump(opage)));
                              }
                              switch (dwdpag) {
                              case SAMEDP:
                                   break;
                              case MAKEDP:
                                   strcpy(workpag->page[msoidx].destpage,dpage);
                                   addstump(curstump,nmsoup(msoidx),dpage,0);
                                   break;
                              case MOVEDP:
                                   strcpy(workpag->page[msoidx].destpage,dpage);
                                   upsib=nmsoup(msoidx);
                                   movstump(stpoff(fndstump(dpage)),
                                            strlen(stpoff(curstump)->name)+
                                                     stpoff(curstump)->tx+2,
                                            (upsib ? ydepth(stpoff(upsib))+1 :
                                                     stpoff(curstump)->ty+1),
                                            curstump,upsib,nmsodn(msoidx));
                                   break;
                              case COPYDP:
                                   upsib=nmsoup(msoidx);
                                   cpyptr=cpystump(stpoff(fndstump(dpage)));
                                   movstump(cpyptr,
                                            strlen(stpoff(curstump)->name)+
                                                     stpoff(curstump)->tx+2,
                                            (upsib ? ydepth(stpoff(upsib))+1 :
                                                     stpoff(curstump)->ty+1),
                                            curstump,upsib,nmsodn(msoidx));
                                   strcpy(workpag->page[msoidx].destpage,
                                          cpyptr->name);
                                   break;
                              }
                         }
                         emodun=1;
                    }
                    else {
                         eemstt=gonstt(EMPSTT,EMSSTT,EMPSTT,EMSSTT);
                    }
               }
               break;
          }
     }
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
}

GBOOL
isvslc(
INT c,
CHAR *stg)
{
     if (isselc(c)) {
          stg[0]=toupper(c);
     }
     return(FALSE);
}

INT
mcnpag(VOID)
{
     CHAR *savscn,choice[2]={""};
     INT retval=0;

     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     explodeto(scntbl[MESSCN],0,12,47,23,16,6);
     while (edtval(16+15,6+10,sizeof(choice),choice,validig,0)) {
          if (choice[0] == '1') {
               retval=MOVEDP;
               break;
          }
          else if (choice[0] == '2') {
               retval=COPYDP;
               break;
          }
          else if (choice[0] == '3') {
               break;
          }
          printf("\7");
     }
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
     return(retval);
}

INT
crnpag(VOID)
{
     CHAR *savscn,yesans[YONSIZ]="Yes";
     INT retval=0;

     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     explodeto(scntbl[MESSCN],0,8,49,11,15,11);
     if (edtval(15+45,11+2,YONSIZ,yesans,validyn,MCHOICE)) {
          if (yesans[0] == 'Y') {
               retval=COPYDP;
          }
     }
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
     return(retval);
}

INT
xistsc(c)
INT c;
{
     INT i;

     for (i=0 ; i < MAXSEL ; i++) {
          if (i != msoidx && toupper(c) == workpag->page[i].selchr && c != '\0') {
               return(1);
          }
     }
     return(0);
}

VOID
movemso(VOID)
{
     static struct mnupag *tmpage=NULL;
     CHAR *savscn,moveto[3]="";
     INT to,i,stn,newty,upsib,dnsib;

     if (tmpage == NULL) {
          tmpage=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     if (workpag->page[msoidx].destpage[0] == '\0') {
          return;
     }
     updpag();
     movmem(workpag,savepag,sizeof(struct mnupag));
     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     explodeto(scntbl[SEASCN],29,6,57,8,26,9);
     while (edtval(51,10,sizeof(moveto),moveto,validig,0)) {
          if ((to=atoi(moveto)-1) >= 0 && to < MAXSEL) {
               if (to == msoidx) {
                    break;
               }
               upsib=nmsoup(to);
               dnsib=nmsodn(to);
               stn=fndstump(workpag->page[msoidx].destpage);
               if ((!upsib && to > msoidx) || (!dnsib && to < msoidx)) {
                    newty=stpoff(stn)->ty;
               }
               else {
                    newty=(to > msoidx ? ydepth(stpoff(upsib))+1
                                          : stpoff(dnsib)->ty);
               }
               movstump(stpoff(stn),stpoff(stn)->tx,newty,curstump,upsib,dnsib);
               movmem(workpag,tmpage,sizeof(struct mnupag));
               if (workpag->page[to].destpage[0] == '\0') {
                    setmem(&workpag->page[msoidx],sizeof(struct pglink),0);
               }
               else if (msoidx > to) {
                    for (i=msoidx-1 ; i >= to ; i--) {
                         shuflo(i,i+1);
                    }
               }
               else {
                    for (i=msoidx+1 ; i < to+1 ; i++) {
                         shuflo(i,i-1);
                    }
               }
               movmem(&tmpage->page[msoidx],&workpag->page[to],
                  sizeof(struct pglink));
               break;
          }
          printf("\7");
     }
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
}

VOID
shuflo(fromsl,tosl)
INT fromsl,tosl;
{
     movmem(&workpag->page[fromsl],&workpag->page[tosl],sizeof(struct pglink));
}

VOID
delmso(VOID)
{
     INT savstump;

     if (workpag->page[msoidx].selchr != '\0' && rusure("No")) {
          updpag();
          movmem(workpag,savepag,sizeof(struct mnupag));
          savstump=curstump;
          if ((curstump=fndstump(workpag->page[msoidx].destpage)) == 0) {
               catastro("STUMP/PAGES MISMATCH");
          }
          cursiz(GVIDNOCURS);
          delstump(stpoff(curstump));
          rstcur();
          curstump=savstump;
          rdomso();
     }
}

VOID
updk4g(x,y)
INT x,y;
{
     sstatr((workpag->flags&CNGOTO) ? 0x2F : 0x2A);
     printfat(x-23,y,"%s","Key Required for \"GO\": ");
     sstatr((workpag->flags&CNGOTO) ? 0x2E : 0x2A);
     printfat(x,y,"%-15s",workpag->golock);
     sstatr(0x2E);
}

VOID
uemlttl(emlstg,ttlstg)
CHAR *emlstg;
CHAR *ttlstg;
{
     sstatr((workpag->flags&AUTPAG) ? 0x2A : 0x2F);
     if (csedit) {
          printfat(17,6+1,"%s","Icon menu style?");
     }
     else {
          printfat(4,6+1,"%s","Edit the way this menu looks?");
     }
     printfat(22,7+1,"%s","Page Title:");
     if (!(workpag->flags&AUTPAG)) {
          if (workpag->flags&DFTDSP) {
               printfat(39,6+1,"%s",csedit ? "(now set to show icons)        "
                   : "(now set to display default)");
          }
          else {
               printfat(39,6+1,"%s",csedit ? "(now set to display a list box)"
                  : "(now set to display a file) ");
          }
     }
     else {
          printfat(39,6+1,"%s","                            ");
     }
     sstatr((workpag->flags&AUTPAG) ? 0x2A : 0x2E);
     printfat(34,6+1,"%s",emlstg);
     printfat(34,7+1,"%s",ttlstg);
     sstatr(0x2E);
}

VOID
mdintf(VOID)
{
     CHAR *savscn;
     INT cho,nmexts=0,pikone=1,savedtc;
     CHAR *crtmnu[3]={
          " Use default menu",
          " Create your own Menu",
          NULL
     };
     static INT edtlng[MAXEXS];
     static CHAR *ptr,*edtmnu[MAXEXS],filn[OFNSIZ],cmdbuf[128+20];

     savedtc=edtvalc;
     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     if (workpag->fname[0] == '\0' || (workpag->flags&DFTDSP)) {
          explodeto(scntbl[SEASCN],0,12,23,15,25,10);
          proff(0,0);
          selatr=0x7F;
          nslatr=0x3F;
          switch (choowd(crtmnu,1,26,11,47,12,TRUE)) {
          case -ESC:
          case 0:
               workpag->flags|=DFTDSP;
               pikone=0;
               break;
          case 1:
               stzcpy(workpag->fname,workpag->pagnam,9);
               workpag->flags&=~DFTDSP;
               break;
          }
     }
     fnmcse(workpag->fname);
     if (pikone) {
          nmexts=bldchl(edtmnu,workpag->fname,edtlng);
     }
     while (pikone) {
          explodeto(scntbl[MLTLNG],0,0,35,6,22,9);
          proff(0,0);
          selatr=0x7F;
          nslatr=0x3F;
          pikone=0;
          if ((cho=choowd(edtmnu,0,23,10,56,14,TRUE)) == 0) {
               workpag->flags|=DFTDSP;
          }
          else if (cho == nmexts-1) {
               explodeto(scntbl[SEASCN],19,3,53,5,23,10);
               edtval(48,10+1,9,workpag->fname,isfnx,needupc() ? ALLCAPS : 0);
               frechl(edtmnu,nmexts);
               nmexts=bldchl(edtmnu,workpag->fname,edtlng);
               pikone=1;
          }
          else if (cho != -ESC) {
               if (canedit(languages[edtlng[cho]])) {
                    stzcpy(filn,&edtmnu[cho][6],OFNSIZ);
                    if ((ptr=strchr(filn,' ')) != NULL) {
                         *ptr='\0';
                    }
                    sprintf(cmdbuf,languages[edtlng[cho]]->editor,filn,filn);
                    edtoff(cmdbuf,NULL,0,filn);
               }
          }
     }
     if (nmexts > 0) {
          frechl(edtmnu,nmexts);
     }
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
     edtvalc=savedtc;
}

INT
bldchl(list,pnam,lnglst)           /* build a choose list for editing menu */
CHAR **list;                       /* list for choose items                */
CHAR *pnam;                        /* page name list is for                */
INT *lnglst;                       /* list of languages for items          */
{
     INT i,num;
     CHAR *ptr,tmpstg[80];

     list[0]=" Use default menu display";
     num=1;
     for (i=0 ; i < nlingo ; i++) {
          if (num < MAXEXS-2 && newext(list,num,languages[i]->extibm)) {
               stzcpy(tmpstg,spr(" Edit %s%s using %s",pnam,
                      languages[i]->extibm,firstwd(languages[i]->editor)),80);
               if ((ptr=strchr(lastwd(tmpstg),'.')) != NULL) {
                    *ptr='\0';
               }
               lnglst[num]=i;
               list[num]=alcmem(strlen(tmpstg)+1);
               strcpy(list[num++],tmpstg);
          }
          if (num < MAXEXS-2 && newext(list,num,languages[i]->extans)) {
               stzcpy(tmpstg,spr(" Edit %s%s using %s",pnam,
                      languages[i]->extans,firstwd(languages[i]->editor)),80);
               if ((ptr=strchr(lastwd(tmpstg),'.')) != NULL) {
                    *ptr='\0';
               }
               lnglst[num]=i;
               list[num]=alcmem(strlen(tmpstg)+1);
               strcpy(list[num++],tmpstg);
          }
          if (num < MAXEXS-2 && newext(list,num,languages[i]->extasc)) {
               stzcpy(tmpstg,spr(" Edit %s%s using %s",pnam,
                      languages[i]->extasc,firstwd(languages[i]->editor)),80);
               if ((ptr=strchr(lastwd(tmpstg),'.')) != NULL) {
                    *ptr='\0';
               }
               lnglst[num]=i;
               list[num]=alcmem(strlen(tmpstg)+1);
               strcpy(list[num++],tmpstg);
          }
     }
     list[num++]=" Use different file name(s)";
     list[num]=NULL;
     return(num);
}

INT                                /* see if RIP version of menu page file */
canedit (edtlng)                   /*    is editable                       */
struct lingo *edtlng;              /*      current language info           */
{
     CHAR *savscn,*nopntscn;
     INT savcur,savx,savy;

     if (!samend(edtlng->name,RIPSFX)
         || !samein("RIPAINT.DLL",edtlng->editor)) {
          return(1);
     }
     if (isfile("RIPAINT.DLL")) {
          return(1);
     }
     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     savcur=curcurs();
     savx=curcurx();
     savy=curcury();
     cursiz(GVIDNOCURS);
     iniscn("galnrip.scn",nopntscn=alcmem(GVIDSCNSIZ));
     explode(nopntscn,11,5,65,17);
     sstatr(0x4E);
     locate(34,8);
     printf("%s",edtlng->name);
     sstatr(0x4F);
     printf(" version");
     locate(13,9);
     printf("of this menu page file, you'll need a copy of the");
     getchc();
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
     free(nopntscn);
     locate(savx,savy);
     cursiz(savcur);
     return(0);
}

VOID
frechl(list,num)                   /* free a choose list for editing menu  */
CHAR **list;                       /* list for choose items                */
INT num;                           /* number of items in choose list       */
{
     INT i;

     for (i=1 ; i < num-1 ; i++) {
          free(list[i]);
     }
}

INT
newext(list,num,ext)               /* is this a new extension?             */
CHAR **list;                       /* list of files (in choose() form)     */
INT num;                           /* number of elements in the list       */
CHAR *ext;                         /* extension to check on                */
{
     INT i;
     CHAR *ptr;

     for (i=0 ; i < num ; i++) {
          if ((ptr=strchr(list[i],'.')) != NULL) {
               if (sameas(firstwd(ptr),ext)) {
                    return(0);
               }
          }
     }
     return(1);
}

INT
gonstt(upstt,dnstt,lfstt,rtstt)
INT upstt,dnstt,lfstt,rtstt;
{
     switch (edtvalc) {
     case CRSRUP:
          return(upstt);
     case '\r':
     case CRSRDN:
          return(dnstt);
     case CRSRLF:
     case BAKTAB:
          return(lfstt);
     case CRSRRT:
     case TAB:
     default:
          return(rtstt);
     }
}

INT
gonmso(curstt)
INT curstt;
{
     rdomso();
     switch (edtvalc) {
     case CRSRUP:
          if (msoidx == 0 || msoidx == SPLITN) {
               rmsobx();
               msoidx=0;
               return((workpag->flags&AUTPAG) ? MAMSTT : EMTSTT);
          }
          msoidx--;
          return(curstt);
     case '\r':
     case CRSRDN:
          if (++msoidx == MAXSEL) {
               rmsobx();
               msoidx--;
               return(SVMSTT);
          }
          return(curstt);
     case CRSRRT:
     case TAB:
          if (curstt == ESCSTT) {
               return(ESDSTT);
          }
          msoidx=(msoidx < SPLITN ? msoidx+SPLITN : msoidx-SPLITN);
          msoidx=min(msoidx,24);
          return(ESCSTT);
     case CRSRLF:
     case BAKTAB:
     default:
          if (curstt == ESDSTT && !csedit) {
               return(ESCSTT);
          }
          msoidx=(msoidx < SPLITN ? msoidx+SPLITN : msoidx-SPLITN);
          msoidx=min(msoidx,24);
          return(ESDSTT);
     }
}

VOID
rdomso(VOID)
{
     INT i;
     CHAR dots[SHDSIZ]={"ùùùùùùùùùùùùùùùùùùùùùùùùùùùùùù"};

     sstatr(0x2E);
     cursact(0);
     for (i=0 ; i < MAXSEL ; i++) {
          if (!csedit) {
               locate((i < SPLITN ? 7 : 43),9+(i%SPLITN)+1);
               printf("%c",(workpag->page[i].selchr == '\0' ? 'ù' :
                    workpag->page[i].selchr));
          }
          locate((i < SPLITN ? 9 : (csedit ? 43 : 45)),9+(i%SPLITN)+1);
          printf("%-30s",(workpag->page[i].selchr == '\0' ? dots :
                  workpag->page[i].shortd));
     }
     cursact(1);
}

VOID
rmsobx(VOID)
{
     nsexploto(scntbl[csedit ? CSMSCN : EMNSCN],11,14,33,18,52,1+1);
}

VOID
amsobx(VOID)
{
     nsexploto(scntbl[SEASCN],58,0,79,4,52,1+1);
}

VOID
gotopg(VOID)
{
     static CHAR srchstg[PNMSIZ];
     struct stump *sp;

     rgtcurs();
     explodeto(scntbl[SEASCN],0,0,30,2,25,8);
     if (edtval(14+24,1+8,PNMSIZ,srchstg,istxvc,ALLCAPS)) {
          if ((sp=mchstump(srchstg)) != NULL) {
               jmp2txy(sp->tx+1,sp->ty,strlen(sp->name));
          }
          else {
               errwin(SEASCN,0,3,18,5,30,12);
          }
     }
     drawtree(tiulx,tiuly,tiulx+TWXSIZ-1,tiuly+TWYSIZ-1);
     curstump=rvtcurs();
}

VOID
seapag(VOID)
{
     CHAR *savscn;
     INT i,match=0;
     struct stump *sp,*ret;
     static CHAR edtstg[PNMSIZ];

     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     explodeto(scntbl[SEASCN],40,19,79,24,19,9);
     if (edtval(33,13,PNMSIZ,edtstg,isastg,0)) {
          for (sp=stpoff(1),i=1 ; i < nstumps ; i++) {
               sp=stpoff(i);
               if (sp->ty > sy2ty(cury) && (ret=ismtch(edtstg,sp)) != NULL) {
                    sp=ret;
                    match=1;
                    break;
               }
          }
          if (!match) {
               for (sp=stpoff(1),i=1 ; i < nstumps ; i++) {
                    sp=stpoff(i);
                    if (sp->ty < sy2ty(cury) && (ret=ismtch(edtstg,sp)) != NULL) {
                         sp=ret;
                         match=1;
                         break;
                    }
               }
               if (!match) {
                    if ((sp=ismtch(edtstg,sp=stpoff(curstump))) != NULL) {
                         match=1;
                    }
               }
          }
          if (!match) {
               errwin(SEASCN,0,3,18,5,30,10);
          }
     }
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
     if (match) {
          jmp2txy(sp->tx+1,sp->ty,strlen(sp->name));
     }
}

struct stump *
ismtch(seastg,sp)                  /* (searching) is this page a match?    */
CHAR *seastg;                      /* string being searched for            */
struct stump *sp;                  /* stump being searched right now       */
{
     INT j;
     static struct mnupag *page=NULL;
     struct stump *retval=NULL;

     if (page == NULL) {
          page=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     if (!dfaAcqEQ(page,mbbkey(sp->name),0)) {
          catastro("CAN'T FIND %s PAGE!",sp->name);
     }
     unpack(page);
     if (page->flags&MDLPAG) {
          if (samein(seastg,page->modnam) || samein(seastg,page->cmdstg)) {
               retval=sp;
          }
     }
     else if (page->flags&FILPAG) {
          if (samein(seastg,page->fname)) {
               retval=sp;
          }
     }
     else {
          for (j=0 ; j < MAXSEL ; j++) {
               if (page->page[j].selchr != '\0' && (samein(seastg,page->page[j].destpage)
                 || samein(seastg,page->page[j].shortd) ||
                 (csedit && samein(seastg,page->page[j].longd)))) {
                    retval=sp;
               }
          }
          if (j != MAXSEL) {
               retval=stpoff(fndstump(page->page[j].destpage));
          }
     }
     if (samein(seastg,page->pagnam)) {
          retval=sp;
     }
     return(retval);
}

VOID
addpg(VOID)
{
     CHAR *savscn,pagnam[PNMSIZ]="";

     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     explodeto(scntbl[SEASCN],25,16,64,18,20,13);
     while (edtval(20+23,13+1,PNMSIZ,pagnam,istxvc,ALLCAPS)) {
          if (pagnam[0] != '\0' && !dfaQueryEQ(mbbkey(pagnam),0)) {
               addstump(0,0,pagnam,0);
               break;
          }
          else if (pagnam[0] != '\0') {
               errwin(SEASCN,0,6,28,8,26,10);
          }
          else {
               printf("\7");
          }
     }
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
     drawtree(tiulx,tiuly,tiulx+TWXSIZ-1,tiuly+TWYSIZ-1);
     curstump=rvtcurs();
}

VOID
delpg(VOID)
{
     struct stump *sp;
     static CHAR nxtsnm[PNMSIZ];

     if ((sp=nearups()) == NULL) {
          if ((sp=neardns()) == NULL) {
               sp=stpoff(1);
          }
     }
     strcpy(nxtsnm,sp->name);      /* save the name since it might relocate*/
     if (curstump > 1) {           /* can't delete TOP either              */
          if (rusure("No")) {
               cursiz(GVIDNOCURS);
               delstump(stpoff(curstump));
               curstump=0;         /* there isn't really a curstump now    */
               rstcur();
          }
     }
     sp=stpoff(fndstump(nxtsnm));
     jmp2txy(sp->tx+1,sp->ty,strlen(sp->name));
     drawtree(tiulx,tiuly,tiulx+TWXSIZ-1,tiuly+TWYSIZ-1);
     rvtcurs();
}

VOID
orphan(sptr)
struct stump *sptr;
{
     INT shfamt;

     if (sptr->child) {
          shfamt=-(ydepth(sptr)-sptr->ty);
          dxystu(stpoff(sptr->child),-(stpoff(sptr->child)->tx),getmty()-sptr->ty);
          shiftt(sptr->ty+1,0,shfamt);
          sptr->child=0;
     }
     renparto("TOP",0);
}

VOID
renparto(newpar,paridx)
CHAR *newpar;
INT paridx;
{
     static struct mnupag *parent=NULL;
     struct stump *sp;
     INT i;

     if (parent == NULL) {
          parent=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     for (i=0 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sp->parent == curstump) {
               sp->parent=paridx;
               if (dfaQueryEQ(mbbkey(sp->name),0)) {
                    dfaAbsRec(parent,0);
                    unpack(parent);
                    if (paridx == 0) {
                         sp->dnsib=sp->upsib=0;
                         parent->flags|=TPOTRE;
                    }
                    strcpy(parent->parpag,newpar);
                    savepage(parent,FALSE);
               }
          }
     }
}

VOID
losedp(sptr)
struct stump *sptr;
{
     static struct mnupag *tmppag=NULL;
     INT shfamt,oldty;

     if (tmppag == NULL) {
          tmppag=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     stpoff(sptr->upsib)->dnsib=sptr->dnsib;
     stpoff(sptr->dnsib)->upsib=sptr->upsib;
     if (!sptr->upsib) {
          stpoff(sptr->parent)->child=sptr->dnsib;
     }
     sptr->parent=sptr->upsib=sptr->dnsib=0;
     oldty=sptr->ty;
     shfamt=-(ydepth(sptr)-sptr->ty+1);
     dxystu(sptr,-sptr->tx,getmty()-sptr->ty+1);
     shiftt(oldty,0,shfamt);
     if (dfaQueryEQ(mbbkey(sptr->name),0)) {
          dfaAbsRec(tmppag,0);
          unpack(tmppag);
          tmppag->flags|=TPOTRE;
          strcpy(tmppag->parpag,"TOP");
          savepage(tmppag,FALSE);
     }
}

VOID
dxystu(sptr,dx,dy)
struct stump *sptr;
INT dx,dy;
{
     do {
          sptr->tx+=dx;
          sptr->ty+=dy;
          if (sptr->child) {
               dxystu(stpoff(sptr->child),dx,dy);
          }
     } while (sptr->dnsib && (sptr=stpoff(sptr->dnsib)) != NULL);
}

VOID
cpmsonam(VOID)
{
     static struct mnupag *tempag=NULL;
     INT i;

     if (tempag == NULL) {
          tempag=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     if (stpoff(curstump)->parent) {
          dfaGetEQ(tempag,mbbkey(stpoff(stpoff(curstump)->parent)->name),0);
          unpack(tempag);
          for (i=0 ; i < MAXSEL; i++) {
               if (sameas(tempag->page[i].destpage,savepag->pagnam)) {
                    strcpy(tempag->page[i].destpage,workpag->pagnam);
                    break;
               }
          }
          savepage(tempag,FALSE);
     }
}

struct stump *
nearups(VOID)
{
     INT i;
     struct stump *cursp,*sp,*nearest;

     cursp=stpoff(curstump);
     if (cursp->upsib) {
          return(stpoff(cursp->upsib));
     }
     for (i=0,nearest=NULL ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sp->ty < cursp->ty) {
               if (nearest == NULL || nearest->ty <= sp->ty) {
                    nearest=sp;
               }
          }
     }
     return(nearest);
}

struct stump *
neardns(VOID)
{
     INT i;
     struct stump *cursp,*sp,*nearest;

     cursp=stpoff(curstump);
     if (cursp->dnsib) {
          return(stpoff(cursp->dnsib));
     }
     for (i=0,nearest=NULL ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sp->ty > cursp->ty) {
               if (nearest == NULL || nearest->ty >= sp->ty) {
                    nearest=sp;
               }
          }
     }
     return(nearest);
}

VOID
jmp2txy(jx,jy,minlen)
INT jx,jy,minlen;
{
     INT oldtix,oldtiy;

     oldtix=tiulx;
     oldtiy=tiuly;
     if (curstump) {               /* in case a page was deleted           */
          rgtcurs();
     }
     if (!in(jx,tiulx,tiulx+TWXSIZ-minlen)) {
          tiulx=(jx < tiulx ? jx : tiulx+(jx-(tiulx+TWXSIZ-minlen)));
     }
     if (!in(jy,tiuly,tiuly+TWYSIZ-1)) {
          tiuly=(jy < tiuly ? jy : tiuly+(jy-(tiuly+TWYSIZ-1)));
     }
     curx=tx2sx(jx);
     cury=ty2sy(jy);
     if (oldtix != tiulx || oldtiy != tiuly) {
          drawtree(tiulx,tiuly,tiulx+TWXSIZ-1,tiuly+TWYSIZ-1);
     }
     curstump=rvtcurs();
}

INT
rvtcurs(VOID)
{
     struct stump *sp;
     INT i;

     for (i=1 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sy2ty(cury) == sp->ty && sx2tx(curx) > sp->tx
           && sx2tx(curx) <= sp->tx+strlen(sp->name)) {
               drawstump(sp,tiulx,tiulx+TWXSIZ-1,0);
               return(i);
          }
     }
     return(0);
}

VOID
rgtcurs(VOID)
{
     drawstump(stpoff(curstump),tiulx,tiulx+TWXSIZ-1,1);
}

VOID
drawtree(ultx,ulty,lrtx,lrty)
INT ultx,ulty,lrtx,lrty;
{
     INT i,iy,endy;
     struct stump *sp;

     cursiz(GVIDNOCURS);
     setatr(TREATR);
     clrarea(TWULX,TWULY,TWLRX,TWLRY,(color ? "\40\37" : "\40\7"));
     for (i=1 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (in(sp->ty,ulty,lrty) && txinsx(sp,ultx,lrtx)) {
               drawstump(sp,ultx,lrtx,1);
          }
          if (sp->ty < lrty && sp->dnsib && stpoff(sp->dnsib)->ty > ulty
           && in(sp->tx,ultx,lrtx)) {
               iy=(sp->ty < ulty ? ulty : sp->ty+1);
               endy=(stpoff(sp->dnsib)->ty > lrty ? lrty :
                                                   stpoff(sp->dnsib)->ty-1);
               for ( ; iy <= endy ; iy++) {
                    locate(tx2sx(sp->tx),ty2sy(iy));
                    printf("³");
               }
          }
     }
     rstcur();
}

INT
txinsx(sp,lxb,rxb)
struct stump *sp;
INT lxb,rxb;
{
     if (sp->tx+strlen(sp->name)+2 >= lxb && sp->tx <= rxb) {
          return(1);
     }
     return(0);
}

VOID
drawstump(stuptr,lxb,rxb,regatr)
struct stump *stuptr;
INT lxb,rxb,regatr;
{
     INT i,buflen,startb,endb;
     UINT coffset;
     CHAR chrbuf[PNMSIZ+2],atrbuf[PNMSIZ+2];

     atrbuf[0]=scncolor(TREATR);
     chrbuf[0]=(stuptr->parent ? (stuptr->dnsib ? 'Ã' : 'À') : ' ');
     setmem(atrbuf+1,strlen(stuptr->name),
            scncolor((regatr ? (stuatr(stuptr)|0x10) : (stuatr(stuptr)|0x40))));
     strcpy(chrbuf+1,stuptr->name);
     chrbuf[buflen=(strlen(stuptr->name)+1)]=(stuptr->child ? 'Ä' : ' ');
     atrbuf[buflen++]=scncolor(TREATR);
     chrbuf[buflen]=(stuptr->child ? '¿' : ' ');
     atrbuf[buflen]=scncolor(TREATR);
     startb=(stuptr->tx < lxb ? lxb-stuptr->tx : 0);
     endb=(stuptr->tx+buflen > rxb ? rxb-stuptr->tx : buflen);


     coffset=gvscnoff(tx2sx(stuptr->tx+startb),ty2sy(stuptr->ty));
     for (i=startb ; i <= endb ; i++,coffset+=2) {
          scnputc(coffset,chrbuf[i]);
          scnputc(coffset+1,atrbuf[i]);
     }
}

INT
stuatr(stuptr)
struct stump *stuptr;
{
     if (stuptr->flags&ISAUTO) {
          return(IASATR&0x0F);
     }
     if (stuptr->flags&ISFILE) {
          return(IFSATR&0x0F);
     }
     if (stuptr->flags&ISMODU) {
          return(IMSATR&0x0F);
     }
     if (stuptr->flags&ISCSMD) {
          return(ICSATR&0x0F);
     }
     return(TREATR&0x0F);
}

VOID
clrarea(culx,culy,clrx,clry,clrstg)
INT culx,culy,clrx,clry;
CHAR *clrstg;
{
     INT i;

     for (i=culy ; i <= clry ; i++) {
          scnputw(gvscnoff(culx,i),clrstg[0],clrstg[1],clrx-culx+1);
     }
}

VOID
addstump(parent,upsib,name,flags)
INT parent,upsib;
CHAR *name;
INT flags;
{
     static struct mnupag *newpag=NULL;
     struct stump *sptr;

     if (newpag == NULL) {
          newpag=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     if (nstumps == maxstp) {
          catastro("%d PAGE LIMIT EXCEEDED",maxstp);
     }
     sptr=stpoff(nstumps);
     setmem(sptr,sizeof(struct stump),0);
     strcpy(sptr->name,name);
     if (parent) {
          sptr->tx=stpoff(parent)->tx+strlen(stpoff(parent)->name)+2;
          sptr->ty=(upsib ? ydepth(stpoff(upsib))+1 : stpoff(parent)->ty+1);
          sptr->parent=parent;
     }
     else {
          sptr->ty=getmty()+1;
     }
     sptr->flags|=flags;
     shiftt(sptr->ty,0,1);
     if (upsib) {
          sptr->upsib=upsib;
          if (stpoff(upsib)->dnsib) {
               sptr->dnsib=stpoff(upsib)->dnsib;
               stpoff(stpoff(upsib)->dnsib)->upsib=nstumps;
          }
          stpoff(upsib)->dnsib=nstumps;
     }
     else if (parent != 0) {
          if (stpoff(parent)->child) {
               sptr->dnsib=stpoff(parent)->child;
               stpoff(stpoff(parent)->child)->upsib=nstumps;
          }
          stpoff(parent)->child=nstumps;
     }
     timaxx=getmtx();
     timaxy=getmty();
     nstumps++;
     setmem(newpag,sizeof(struct mnupag),0);
     strcpy(newpag->menutype,mbbkey(name));
     strcpy(newpag->parpag,(parent == 0 ? "TOP" : stpoff(parent)->name));
     if (parent == 0) {
          newpag->flags|=TPOTRE;
     }
     newpag->flags|=(DFTDSP+CNGOTO);
     savepage(newpag,TRUE);
}

VOID
shiftt(fromy,xamt,yamt)
INT fromy,xamt,yamt;
{
     struct stump *sptr;
     INT i;

     for (i=0 ; i < nstumps ; i++) {
          sptr=stpoff(i);
          if (sptr->ty >= fromy) {
               sptr->tx+=xamt;
               sptr->ty+=yamt;
          }
     }
}

VOID
movstump(sp,newtx,newty,parent,upsib,dnsib)
struct stump *sp;
INT newtx,newty,parent,upsib,dnsib;
{
     INT oldty,bsiz,spidx;
     static struct mnupag *mp=NULL;

     if (mp == NULL) {
          mp=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     spidx=fndidx(sp);
     if (!sp->upsib) {
          stpoff(sp->parent)->child=sp->dnsib;
     }
     else {
          stpoff(sp->upsib)->dnsib=sp->dnsib;
     }
     stpoff(sp->dnsib)->upsib=sp->upsib;
     bsiz=ydepth(sp)-sp->ty+1;
     shiftt(newty,0,bsiz);
     oldty=sp->ty;
     sp->dnsib=0;
     dxystu(sp,newtx-sp->tx,newty-sp->ty);
     shiftt(oldty,0,-bsiz);
     stpoff(sp->upsib=upsib)->dnsib=spidx;
     stpoff(sp->dnsib=dnsib)->upsib=spidx;
     sp->parent=parent;
     if (!sp->upsib) {
          stpoff(parent)->child=spidx;
     }
     dfaGetEQ(mp,mbbkey(sp->name),0);
     unpack(mp);
     if (parent != 0) {
          mp->flags&=~TPOTRE;
     }
     strcpy(mp->parpag,(parent ? stpoff(parent)->name : "TOP"));
     savepage(mp,FALSE);
}

struct stump *
cpystump(sptr)
struct stump *sptr;
{
     INT newpar;

     newpar=cpyone(sptr,0,0);
     if (sptr->child) {
          cpysutl(stpoff(sptr->child),newpar,0);
     }
     return(stpoff(newpar));
}

VOID
cpysutl(sp,paridx,upsidx)
struct stump *sp;
INT paridx,upsidx;
{
     do {
          upsidx=cpyone(sp,paridx,upsidx);
          if (sp->child) {
               cpysutl(stpoff(sp->child),upsidx,0);
          }
     } while (sp->dnsib && (sp=stpoff(sp->dnsib)) != NULL);
}

INT
cpyone(sp,paridx,upsidx)
struct stump *sp;
INT paridx,upsidx;
{
     CHAR name[PNMSIZ];
     static struct mnupag *oldmnu=NULL,*newmnu=NULL;
     INT l,nidx,trydig='2';

     if (oldmnu == NULL) {
          oldmnu=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     if (newmnu == NULL) {
          newmnu=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     stzcpy(name,sp->name,PNMSIZ);
     nidx=(((l=strlen(name)) < PNMSIZ-1 && !isdigit(name[l-1])) ? l : l-1);
     do {
          name[nidx]=trydig;
          if (trydig == 'Z') {
               trydig='2';
               if (++nidx >= PNMSIZ-1) {
                    nidx=0;
               }
          }
          else {
               trydig=(trydig == '9' ? 'A' : trydig+1);
          }
     } while (fndstump(name));
     addstump(paridx,upsidx,name,sp->flags);
     if (paridx != 0) {
          dfaAcqEQ(oldmnu,mbbkey(stpoff(paridx)->name),0);
          unpack(oldmnu);
          for (l=0 ; l < MAXSEL ; l++) {
               if (sameas(oldmnu->page[l].destpage,sp->name)) {
                    strcpy(oldmnu->page[l].destpage,name);
                    break;
               }
          }
          savepage(oldmnu,FALSE);
     }
     dfaAcqEQ(oldmnu,mbbkey(sp->name),0);
     unpack(oldmnu);
     dfaAcqEQ(newmnu,mbbkey(name),0);
     unpack(newmnu);
     switch (oldmnu->flags&(AUTPAG|FILPAG|MDLPAG)) {
     case FILPAG:
          strcpy(newmnu->fname,oldmnu->fname);
          strlwr(newmnu->fname);
          newmnu->flags|=FILPAG;
          break;
     case MDLPAG:
          strcpy(newmnu->modnam,oldmnu->modnam);
          incref(newmnu->modnam);
          strcpy(newmnu->cmdstg,oldmnu->cmdstg);
          newmnu->flags|=MDLPAG;
          if (oldmnu->flags&CSMPAG) {
               newmnu->flags|=CSMPAG;
          }
          break;
     default:
          strcpy(newmnu->fname,oldmnu->fname);
          strlwr(newmnu->fname);
          movmem(oldmnu->page,newmnu->page,MAXSEL*sizeof(struct pglink));
          if (oldmnu->flags&AUTPAG) {
               newmnu->flags|=AUTPAG;
          }
     }
     strcpy(newmnu->golock,oldmnu->golock);
     newmnu->flags&=~CNGOTO;
     if (oldmnu->flags&CNGOTO) {
          newmnu->flags|=CNGOTO;
     }
     newmnu->flags&=~DFTDSP;
     if (oldmnu->flags&DFTDSP) {
          newmnu->flags|=DFTDSP;
     }
     dfaAcqEQ(NULL,mbbkey(stpoff(nstumps-1)->name),0);
     savepage(newmnu,FALSE);
     return(nstumps-1);
}

INT
nmsoup(slot)
INT slot;
{
     INT i;

     for (i=(slot > msoidx ? slot : slot-1) ; i >= 0 ; i--) {
          if (i != msoidx && workpag->page[i].destpage[0] != '\0') {
               return(fndstump(workpag->page[i].destpage));
          }
     }
     return(0);
}

INT
nmsodn(slot)
INT slot;
{
     INT i;

     for (i=(slot >= msoidx ? slot+1 : slot) ; i < MAXSEL ; i++) {
          if (i != msoidx && workpag->page[i].destpage[0] != '\0') {
               return(fndstump(workpag->page[i].destpage));
          }
     }
     return(0);
}

VOID
delstump(sptr)
struct stump *sptr;
{
     static struct mnupag *ifmodu=NULL;

     if (ifmodu == NULL) {
          ifmodu=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     if (sptr->parent) {
          delmsp(stpoff(sptr->parent),sptr->name);
          if (sptr->upsib) {
               stpoff(sptr->upsib)->dnsib=sptr->dnsib;
          }
          else {
               stpoff(sptr->parent)->child=sptr->dnsib;
          }
          stpoff(sptr->dnsib)->upsib=sptr->upsib;
     }
     orphan(sptr);
     shiftt(sptr->ty+1,0,-1);
     dfaGetEQ(ifmodu,mbbkey(sptr->name),0);
     unpack(ifmodu);
     if (ifmodu->flags&MDLPAG) {
          decref(ifmodu->modnam);
     }
     dfaDelete();
     if (--nstumps != curstump) {
          movmem(stpoff(nstumps),sptr,sizeof(struct stump));
          sratob(nstumps,curstump);
     }
}

VOID
delmsp(sptr,mspnam)
struct stump *sptr;
CHAR *mspnam;
{
     static struct mnupag *tp=NULL;
     INT i;

     if (tp == NULL) {
          tp=(struct mnupag *)alcmem(sizeof(struct mnupag));
     }
     dfaGetEQ(tp,mbbkey(sptr->name),0);
     unpack(tp);
     for (i=0 ; i < MAXSEL ; i++) {
          if (sameas(tp->page[i].destpage,mspnam)) {
               setmem(&tp->page[i],sizeof(struct pglink),0);
               break;
          }
     }
     if (i < MAXSEL && sameas(sptr->name,workpag->pagnam)) {
          setmem(&workpag->page[i],sizeof(struct pglink),0);
     }
     savepage(tp,FALSE);
}

VOID
sratob(oldref,newref)
INT oldref,newref;
{
     struct stump *sptr;
     INT i;

     for (i=0 ; i < nstumps ; i++) {
          sptr=stpoff(i);
          sptr->parent=(sptr->parent == oldref ? newref : sptr->parent);
          sptr->child=(sptr->child == oldref ? newref : sptr->child);
          sptr->upsib=(sptr->upsib == oldref ? newref : sptr->upsib);
          sptr->dnsib=(sptr->dnsib == oldref ? newref : sptr->dnsib);
     }
}

INT
fndstump(name)
CHAR *name;
{
     struct stump *sp;
     INT i;

     for (i=1 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sameas(sp->name,name)) {
               return(i);
          }
     }
     return(0);
}

INT
fndidx(sp)
struct stump *sp;
{
     INT i;

     for (i=0 ; i < nstumps ; i++) {
          if (stpoff(i) == sp) {
               return(i);
          }
     }
     catastro("FNDIDX: CAN'T FIND SP INDEX!");
     return(0);
}

struct stump *
mchstump(name)
CHAR *name;
{
     struct stump *sp;
     INT i;

     for (i=1 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sp->ty > sy2ty(cury) && sameto(name,sp->name)) {
               return(sp);
          }
     }
     for (i=1 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sp->ty < sy2ty(cury) && sameto(name,sp->name)) {
               return(sp);
          }
     }
     sp=stpoff(curstump);
     return(sameto(name,sp->name) ? sp : NULL);
}

INT
ydepth(stuptr)
struct stump *stuptr;
{
     if (stuptr->child) {
          stuptr=stpoff(stuptr->child);
          while (stuptr->dnsib) {
               stuptr=stpoff(stuptr->dnsib);
          }
          if (stuptr->child) {
               return(ydepth(stuptr));
          }
     }
     return(stuptr->ty);
}

INT
getmtx(VOID)
{
     struct stump *sp;
     INT i,retval=0;

     for (i=0 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sp->tx > retval) {
               retval=sp->tx;
          }
     }
     return(retval);
}

INT
getmty(VOID)
{
     struct stump *sp;
     INT i,retval=0;

     for (i=0 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sp->ty > retval) {
               retval=sp->ty;
          }
     }
     return(retval);
}

INT
readtree(VOID)
{
     FILE *tfp;
     INT i;
     CHAR *err;
     struct stump *sp;
     struct ffblk oldfb,newfb;

     tfp=fopen(err=csedit ? "wgsmenuc.idx" : "wgsmenus.idx",FOPRB);
     if (tfp == NULL) {
          return(0);
     }
     fndfile(&newfb,"wgsmenu2.dat",0);
     if (fread(&oldfb,sizeof(struct ffblk),1,tfp) != 1
      || oldfb.ff_ftime != newfb.ff_ftime
      || oldfb.ff_fdate != newfb.ff_fdate
      || oldfb.ff_fsize != newfb.ff_fsize) {
          fclose(tfp);
          return(0);
     }
     fscanf(tfp,"%d %d %d\n",&nstumps,&timaxx,&timaxy);
     if (nstumps > maxstp) {
          catastro("%d pages in menu tree! Can't support more than %d.\n"
                   "You might try changing the \"call wgsmtree.bat\" line\n"
                   "in wg.bat to \"call wgsmtree.bat %d\".",
                   nstumps,maxstp,nstumps);
     }
     if (stpblok == NULL) {
          stpblok=alcblok(maxstp,sizeof(struct stump));
  /* WARNING, in DEBUG mode this alcblok takes 20 minutes on a 386DX-20,   */
  /*          if maxstp is left at 6500!                                   */
     }
     for (i=0 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (fscanf(tfp,"%s %d %d %d %d %d %d %d\n",&sp->name,&sp->parent,
            &sp->child,&sp->upsib,&sp->dnsib,&sp->tx,&sp->ty,&sp->flags) != 8) {
               catastro("ERROR READING \"%s\"!",err);
          }
     }
     fclose(tfp);
     return(1);
}

VOID
savetree(VOID)
{
     FILE *tfp;
     INT i;
     CHAR *ec;
     struct stump *sp;
     struct ffblk fb;

     ec=csedit ? "wgsmenuc.idx" : "wgsmenus.idx";
     tfp=fopen(ec,FOPWB);
     if (tfp == NULL) {
          catastro("COULDN'T OPEN \"%s\" FOR WRITING!",ec);
     }
     fndfile(&fb,"wgsmenu2.dat",0);
     fwrite(&fb,sizeof(struct ffblk),1,tfp);
     fprintf(tfp,"%d %d %d\n",nstumps,timaxx,timaxy);
     for (i=0 ; i < nstumps ; i++) {
          sp=stpoff(i);
          fprintf(tfp,"%s %d %d %d %d %d %d %d\n",sp->name,sp->parent,
                       sp->child,sp->upsib,sp->dnsib,sp->tx,sp->ty,sp->flags);
     }
     fclose(tfp);
     markfile(csedit ? "wgsmenus.idx" : "wgsmenuc.idx",&fb,FALSE);
}

struct stump *
stpoff(                            /* get pointer to stump element         */
INT stpnum)                        /*   element number to grab             */
{
     return((struct stump *)ptrblok(stpblok,stpnum));
}

INT
rusure(dftans)
CHAR *dftans;
{
     CHAR *savscn,yonans[YONSIZ];
     INT retval=0;

     strcpy(yonans,dftans);
     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     explodeto(scntbl[SEASCN],31,0,51,2,30,12);
     if (edtval(46,13,YONSIZ,yonans,validyn,MCHOICE)) {
          if (yonans[0] == 'Y') {
               retval=1;
          }
     }
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
     return(retval);
}

VOID
errwin(scn,eulx,euly,elrx,elry,sulx,suly)
INT scn,eulx,euly,elrx,elry,sulx,suly;
{
     CHAR *svescn;

     printf("\7");
     scn2mem(svescn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     explodeto(scntbl[scn],eulx,euly,elrx,elry,sulx,suly);
     cursiz(GVIDNOCURS);
     getchc();
     cursiz(GVIDLILCURS);
     mem2scn(svescn,0,GVIDSCNSIZ);
     free(svescn);
}

GBOOL
isfnx(
INT c)
{
     return((isalnum(c&0xFF) || c == '_' || c == '$' || c == '@' || c == '!'
          || c == '#' || c == '&' || c == '-' || c == '^' || c == '{'
          || c == '}' || c == '(' || c == ')') ? TRUE : FALSE);
}

GBOOL
isfilp(
INT c,
CHAR *stg)
{
     (VOID)stg;
     return((isfnx(c&0xFF)
          || c == '\\'
          || c == ':'
          || c == '.'
          || c == '/') ? TRUE : FALSE);
}

GBOOL
isastg(
INT c)
{
     if (c > 31 && c < 127) {
          return(TRUE);
     }
     return(FALSE);
}

GBOOL
isaxstg(
INT c)
{
     if (c > 31 && c < 255) {
          return(TRUE);
     }
     return(FALSE);
}

GBOOL
iskeyc(
INT c)
{
     return((istxvc(c&0xFF) || c == '#' || c == '=') ? TRUE : FALSE);
}

INT
camidx(GBOOL csmode,GBOOL aamod)
{
     CHAR **mptr;
     INT retval=0;

     mptr=(csmode ? avmlstcs : (aamod ? avmlstaa : avmlst));
     do {
          if (sameas(*mptr,workpag->modnam)) {
               return(retval);
          }
          retval++;
          mptr++;
     } while (*mptr != NULL);
     return(0);
}

INT
getchq(VOID)                       /* get char routine for WGSDRAW         */
{
     return(getchc());
}

VOID
toggmode(VOID)                     /* toggle C/S edit mode                 */
{
     mem2scn(scntbl[MAISCN],0,GVIDSCNSIZ);
     dfaClose(mpbb);
     savetree();
     csedit=!csedit;

     mpbb=dfaOpen("wgsmenu2.dat",sizeof(struct mnupag),NULL);
     if (!readtree()) {
          system("wgsrbt");
          if (!readtree()) {
               catastro("CAN'T BUILD TREE");
          }
     }
     tiulx=tiuly=0;
     drawtree(tiulx,tiuly,tiulx+TWXSIZ-1,tiuly+TWYSIZ-1);
     curx=2;
     cury=1;
     if (!csedit) {
          setatr(0x1B);
          locate(30,0);
          printf("ÍÍÍ");
     }
     locate(14,0);
     setatr(0x70);
     printf(csedit ? "Client/Server Mode " : "Terminal Mode ");
     curstump=rvtcurs();
}

CHAR *
mbbkey(                            /* returns a key depending on edit mode */
CHAR *menuname)                    /* menu name                            */
{
     static CHAR retstr[PNMSIZ+1];

     stzcpy(retstr,(csedit ? "C" : "A"),PNMSIZ+1);
     stzcat(retstr,menuname,PNMSIZ+1);
     return(retstr);
}

CHAR *
pickicon(                          /* select an icon from pop-up list      */
CHAR *curicon)
{
     INT idx,ndefs,def,topico,rloop;
     struct ffblk fb;
     CHAR *sp,*savscn;
     static CHAR **iconlist=NULL;
     CHAR **deficos=NULL,**disklist;
     static INT numicons=0;

     if (iconlist == NULL) {
          ndefs=0;
          for (idx=0 ; idx < nmdfs ; idx++) {
               if (moddat[idx].modnam[0] != '\0'
                  && moddat[idx].defico[0] != '\0') {
                    ndefs++;
               }
          }
          if (ndefs > 0) {
               deficos=(CHAR **)alczer(ndefs*sizeof(CHAR *));
          }
          def=0;
          for (idx=0 ; idx < nmdfs ; idx++) {
               if (moddat[idx].modnam[0] != '\0'
                  && moddat[idx].defico[0] != '\0') {
                    sp=spr("%s.ico",moddat[idx].defico);
                    sp=spr("%-12s  %s",sp,moddat[idx].modnam);
                    strcpy(deficos[def++]=alcmem(strlen(sp)+1),sp);
               }
          }
          def=0;
          if (fnd1st(&fb,"wgsicons"SLS"*.ico",0)) {
               do {
                    def++;
               } while (fndnxt(&fb));
          }
          if (def < 2) {
               return("wgsdef");
          }
          disklist=(CHAR **)alczer(def*sizeof(CHAR *));
          idx=0;
          if (fnd1st(&fb,"wgsicons"SLS"*.ico",0)) {
               do {
                    stzcpy(disklist[idx]=alcmem(FNEXSZ),fb.ff_name,FNEXSZ);
               } while (++idx < def && fndnxt(&fb));
          }
          topico=1+def+ndefs;
          iconlist=(CHAR **)alczer((1+topico)*sizeof(CHAR *));
          numicons=0;
          for (idx=0 ; idx < def ; idx++) {
               if (sameas(disklist[idx],"wgsdef.ico")) {
                    sp="wgsdef.ico    Default icon";
                    for (rloop=0 ; rloop < def ; rloop++) {
                         if (sameas(disklist[rloop],firstwd(sp))) {
                              free(disklist[rloop]);
                              movmem(&disklist[rloop+1],&disklist[rloop],
                                 (def-(rloop+1))*sizeof(CHAR *));
                              def--;
                              break;
                         }
                    }
                    strcpy(iconlist[numicons++]=alcmem(strlen(sp)+1),sp);
                    break;
               }
          }
          if (deficos != NULL) {
               sortstgs(deficos,ndefs);
               for (idx=0 ; idx < ndefs ; idx++) {
                    sp=deficos[idx];
                    if (sp != NULL) {
                         for (rloop=0 ; rloop < def ; rloop++) {
                              if (sameas(disklist[rloop],firstwd(sp))) {
                                   free(disklist[rloop]);
                                   movmem(&disklist[rloop+1],&disklist[rloop],
                                      (def-(rloop+1))*sizeof(CHAR *));
                                   def--;
                                   break;
                              }
                         }
                         strcpy(iconlist[numicons++]=alcmem(strlen(sp)+1),sp);
                         free(sp);
                    }
               }
               free(deficos);
          }
          if (disklist != NULL) {
               sortstgs(disklist,def);
               for (idx=0 ; idx < def ; idx++) {
                    sp=disklist[idx];
                    if (sp != NULL) {
                         strcpy(iconlist[numicons++]=alcmem(strlen(sp)+1),sp);
                         free(sp);
                    }
               }
               free(disklist);
          }
     }
     curicon=spr("%s.ico",curicon);
     idx=0;
     if (curicon[0] != '\0') {
          for (rloop=0 ; rloop < numicons ; rloop++) {
               if (sameto(curicon,iconlist[rloop])) {
                    idx=rloop;
                    break;
               }
          }
     }
     scn2mem(savscn=alcmem(GVIDSCNSIZ),0,GVIDSCNSIZ);
     sp="*";                       /* if "*" returned, ESC was hit.        */
     explodeto(scntbl[MLTLNG],36,0,76,6,27,9);
     selatr=0x70;
     nslatr=0x3F;
     if ((idx=choowd(iconlist,idx,1,1,39,5,TRUE)) != -ESC) {
          sp=iconlist[idx];
     }
     mem2scn(savscn,0,GVIDSCNSIZ);
     free(savscn);
     return(firstwd(sp));
}

VOID
appgprept(VOID)                    /* application-specific GP info (stub)  */
{
}

VOID
appgprecd(VOID)                    /* application-specific GP record (stub)*/
{
}
