#include "all.h"
#include "color.h"
#include "edt.h"
#ifdef unix
        #define SEEK_SET 0
#endif
#ifdef DJ                       /* a.r. */
        #define SEEK_SET 0
        #define clrscr ScreenClear
#endif
#ifdef EMXOS2                   /* a.r. */
        #define SEEK_SET 0
        extern unsigned long startPMSession(void);
        extern unsigned long stopPMSession(unsigned long SessID);
        extern unsigned long oldSession;
        extern int text_saveOS2tmp(void);
        extern int g_get_type(char *t);
        char devtype[60];
#endif

#ifdef __TURBOC__
        #define DASHCHAR 249
        #include "bios.h"
        #include "conio.h"
        #include "dir.h"
#elif DJ                        /* a.r. */
        #define DASHCHAR 249
        #include <gppconio.h>
        #include <dir.h>
#elif EMXOS2                    /* a.r. */
        #define INCL_DOS
        #include <os2.h>
        #include <conio.h>
        #include <sys/types.h>
        #include <sys/dir.h>
        #define DASHCHAR 249
        #define WHITE 15
        #define BLACK 0
#else
        #define DASHCHAR '.'
        #include "vaxconio.h"
#endif

#define true (!false)
#define false 0
#define BEGINDEF extern
#include "begin.h"
#define BCOLOR BLUE
#define FCOLOR MAGENTA
#define HBCOLOR h_bcolor
#define HVCOLOR h_fcolor
#define VCOLOR WHITE

int h_bcolor;
int h_fcolor;
int getsize(void);
char *tabtospace(char *s);
int printdash(int i);
char *gledir(char *s);
int scr_menuval(void);
int scr_menubg(void);
int scr_menuhi(void);
int scr_grey(void);
int gle_redraw(void);
int text_showerror(void);
int text_save(void);
int fner(char *s);
char *strfile(char *s);

int vdelete(int i);
int vinsert(int y, char *s);
int m_ifsend(char *s);
int m_sendline(void);
int minit_extras(void);
int minit_extras(void);
int initmenu(void);
int mystrlen(char *s);
int pick_file(char *d, char *w);
int ncpy(char *d, char *s, int n);
int setvstr(char **d, char *s);
int do_help(char *s);
int text_inkey(void);

extern int ngtxt;
extern char *(*gtxt)[];


struct menu_struct { int x; int y; char *title; int width; int typ; int typ2;
        char *val; char *help; };
typedef struct menu_struct menutype;
struct pmenu_struct {int ci; menutype *menu; };
typedef struct pmenu_struct pmenutype;
pmenutype pmenu[17];
int setmenu(menutype *m,int x, int y, int typ, int typ2, int width, char *title
        , char *val, char *help);
int do_menu(pmenutype *p);
int token_space(void);
int extractmenu(void);
int add_unrecognized(char *s);
int fillinmenu(int nbegin);
int nunrec;

#define  PTXT 0
enum {MEND,MTEXT,MFILE,MTOGON,MTOGOFF,MSUB,MRETURN,MNULL};
enum {SNORM,SROL,SNEXTS,SNEXT,SSTR,STOG,SS,SSIZE,SNOBOX,SAMOVE,SSOFF,SSNULL};
menutype xnamesmenu[] = {
        2,3,    "Xnames ",  64,MTEXT,SROL,PTXT,"xnames",
        2,5,    "Xplaces ", 64,MTEXT,SROL,PTXT,"xplaces",
        0,0,"",         0,MEND,0,0,""};
menutype ynamesmenu[] = {
        2,3,    "Ynames ",  64,MTEXT,SROL,PTXT,"ynames",
        2,5,    "Yplaces ", 64,MTEXT,SROL,PTXT,"yplaces",
        0,0,"",         0,MEND,0,0,""};
menutype x2namesmenu[] = {
        2,3,    "X2names ", 64,MTEXT,SROL,PTXT,"x2names",
        2,5,    "X2places ",    64,MTEXT,SROL,PTXT,"x2places",
        0,0,"",         0,MEND,0,0,""};
menutype y2namesmenu[] = {
        2,3,    "Y2names ", 64,MTEXT,SROL,PTXT,"y2names",
        2,5,    "Y2places ",    64,MTEXT,SROL,PTXT,"y2places",
        0,0,"",         0,MEND,0,0,""};
menutype x2axismenu[] = {

        1,4,    "X2Title ", 27,MTEXT,SNEXTS,PTXT,"x2title",
        37,4,   "Hei ",     4,MTEXT,0,PTXT,"x2title hei",
        46,4,   "Dist ",    3,MTEXT,0,PTXT,"x2title dist",
        55,4,   "Font " ,   4,MTEXT,0,PTXT,"x2title font",
        65,4,   "Color ",   7,MTEXT,0,PTXT,"x2title color",

        1,6,    "X2axis ",  3,MTOGON,SSOFF,PTXT,"x2axis off",
        13,6,   "Min ",     6,MTEXT,0,PTXT,"x2axis min",
        24,6,   "Max ",     6,MTEXT,0,PTXT,"x2axis max",
        35,6,   "Dticks ",  6,MTEXT,0,PTXT,"x2axis dticks",
        49,6,   "Dsubticks ",   6,MTEXT,0,PTXT,"x2axis dsubticks",
        66,6,   "LOG ",     3,MTOGOFF,SS,PTXT,"x2axis log",

        1,8,    "X2labels ",    3,MTOGOFF,SS,PTXT,"x2labels on",
        15,8,   "Hei ",     4,MTEXT,0,PTXT,"x2labels hei",
        24,8,   "Dist ",    4,MTEXT,0,PTXT,"x2labels dist",
        34,8,   "Font ",    4,MTEXT,0,PTXT,"x2labels font",
        44,8,   "Color ",   7,MTEXT,0,PTXT,"x2labels color",
        59,8,   "",     5,MSUB,103,"Names","x2names",
        0,0,"",         0,MEND,0,0,""};

menutype y2axismenu[] = {

        1,4,    "Y2Title ", 27,MTEXT,SNEXTS,PTXT,"y2title",
        37,4,   "Hei ",     4,MTEXT,0,PTXT,"y2title hei",
        46,4,   "Dist ",    3,MTEXT,0,PTXT,"y2title dist",
        55,4,   "Font " ,   4,MTEXT,0,PTXT,"y2title font",
        65,4,   "Color ",   7,MTEXT,0,PTXT,"y2title color",


        1,6,    "Y2axis ",  3,MTOGON,SSOFF,PTXT,"y2axis off",
        12,6,   "Min ",     6,MTEXT,0,PTXT,"y2axis min",
        23,6,   "Max ",     6,MTEXT,0,PTXT,"y2axis max",
        34,6,   "Dticks ",  6,MTEXT,0,PTXT,"y2axis dticks",
        48,6,   "Dsubticks ",   6,MTEXT,0,PTXT,"y2axis dsubticks",
        65,6,   "LOG ",     3,MTOGOFF,SS,PTXT,"y2axis log",

        1,8,    "Y2labels ",    3,MTOGOFF,SS,PTXT,"y2labels on",
        15,8,   "Hei ",     4,MTEXT,0,PTXT,"y2labels hei",
        24,8,   "Dist ",    4,MTEXT,0,PTXT,"y2labels dist",
        34,8,   "Font ",    4,MTEXT,0,PTXT,"y2labels font",
        44,8,   "Color ",   7,MTEXT,0,PTXT,"y2labels color",
        59,8,   "",     4,MSUB,104,"Names","y2names",
        0,0,"",         0,MEND,0,0,""};
menutype fillmenu[] = {
        2,3,    "Fill ",    60,MTEXT,SROL,PTXT,"fill",
        2,5,    "Fill ",    60,MTEXT,SROL,PTXT,"fill",
        2,7,    "Fill ",    60,MTEXT,SROL,PTXT,"fill",
        2,9,    "Fill ",    60,MTEXT,SROL,PTXT,"fill",
        2,11,   "Fill ",    60,MTEXT,SROL,PTXT,"fill",
        0,0,"",         0,MEND,0,0,""};
menutype barmenu[] = {
        2,3,    "Bar ",     60,MTEXT,SROL,PTXT,"bar",
        2,5,    "Bar ",     60,MTEXT,SROL,PTXT,"bar",
        2,7,    "Bar ",     60,MTEXT,SROL,PTXT,"bar",
        2,9,    "Bar ",     60,MTEXT,SROL,PTXT,"bar",
        2,11,   "Bar ",     60,MTEXT,SROL,PTXT,"bar",
        0,0,"",         0,MEND,0,0,""};
menutype letmenu[] = {
        2,3,    "Let ",     60,MTEXT,SROL,PTXT,"let",
        2,5,    "Let ",     60,MTEXT,SROL,PTXT,"let",
        2,7,    "Let ",     60,MTEXT,SROL,PTXT,"let",
        2,9,    "Let ",     60,MTEXT,SROL,PTXT,"let",
        2,11,   "Let ",     60,MTEXT,SROL,PTXT,"let",
        0,0,"",         0,MEND,0,0,""};
menutype xtramenu[] = {
        2,3,    "Xtra ",        60,MTEXT,SROL,PTXT,"xtra",
        2,5,    "Xtra ",        60,MTEXT,SROL,PTXT,"xtra",
        2,7,    "Xtra ",        60,MTEXT,SROL,PTXT,"xtra",
        2,9,    "Xtra ",        60,MTEXT,SROL,PTXT,"xtra",
        2,11,   "Xtra ",        60,MTEXT,SROL,PTXT,"xtra",
        0,0,"",         0,MEND,0,0,""};
/* int x; int y; char *title; int width; int typ; int typ2; char *val; */
menutype graphmenu[278] = {
        1,1,    "Size ",    4,MTEXT,SSIZE,"24","size",
        12,1,   "",     4,MTEXT,0,"18","size",
        19,1,   "Position ",    4,MTEXT,SAMOVE,PTXT,"position",
        34,1,   "",     4,MTEXT,SAMOVE,PTXT,"position",
/*  42,1,   "Lwidth ",  4,MTEXT,0,PTXT,"lwidth", */
        55,1,   "Border ",  3,MTOGON,SNOBOX,PTXT,"nobox",

        1,2,    "Title ",   27,MTEXT,SNEXTS,PTXT,"title",
        37,2,   "Hei ",     4,MTEXT,0,PTXT,"title hei",
        46,2,   "Dist ",    3,MTEXT,0,PTXT,"title dist",
        55,2,   "Font " ,   4,MTEXT,0,PTXT,"title font",
        65,2,   "Color ",   7,MTEXT,0,PTXT,"title color",

        1,3,    "XTitle ",  27,MTEXT,SNEXTS,PTXT,"xtitle",
        37,3,   "Hei ",     4,MTEXT,0,PTXT,"xtitle hei",
        46,3,   "Dist ",    3,MTEXT,0,PTXT,"xtitle dist",
        55,3,   "Font " ,   4,MTEXT,0,PTXT,"xtitle font",
        65,3,   "Color ",   7,MTEXT,0,PTXT,"xtitle color",

        1,4,    "YTitle ",  27,MTEXT,SNEXTS,PTXT,"ytitle",
        37,4,   "Hei ",     4,MTEXT,0,PTXT,"ytitle hei",
        46,4,   "Dist ",    3,MTEXT,0,PTXT,"ytitle dist",
        55,4,   "Font " ,   4,MTEXT,0,PTXT,"ytitle font",
        65,4,   "Color ",   7,MTEXT,0,PTXT,"ytitle color",

        1,5,    "Xaxis ",   3,MTOGON,SSOFF,PTXT,"xaxis off",
        12,5,   "Min ",     6,MTEXT,0,PTXT,"xaxis min",
        23,5,   "Max ",     6,MTEXT,0,PTXT,"xaxis max",
        34,5,   "Dticks ",  6,MTEXT,0,PTXT,"xaxis dticks",
        48,5,   "Dsubticks ",   6,MTEXT,0,PTXT,"xaxis dsubticks",
        65,5,   "LOG ",     3,MTOGOFF,SS,PTXT,"xaxis log",

        1,6,    "Yaxis ",   3,MTOGON,SSOFF,PTXT,"yaxis off",
        12,6,   "Min ",     6,MTEXT,0,PTXT,"yaxis min",
        23,6,   "Max ",     6,MTEXT,0,PTXT,"yaxis max",
        34,6,   "Dticks ",  6,MTEXT,0,PTXT,"yaxis dticks",
        48,6,   "Dsubticks ",   6,MTEXT,0,PTXT,"yaxis dsubticks",
        65,6,   "LOG ",     3,MTOGOFF,SS,PTXT,"yaxis log",

        1,7,    "Xlabels ", 3,MTOGON,SSOFF,PTXT,"xlabels off",
        14,7,   "Hei ",     4,MTEXT,0,PTXT,"xlabels hei",
        23,7,   "Dist ",    4,MTEXT,0,PTXT,"xlabels dist",
        33,7,   "Font ",    4,MTEXT,0,PTXT,"xlabels font",
        43,7,   "Color ",   7,MTEXT,0,PTXT,"xlabels color",
        58,7,   "",     6,MSUB,101,"Xnames","xnames",
        66,7,   "Grid ",    3,MTOGOFF,SS,PTXT,"xaxis grid",

        1,8,    "Ylabels ", 3,MTOGON,SSOFF,PTXT,"ylabels off",
        14,8,   "Hei ",     4,MTEXT,0,PTXT,"ylabels hei",
        23,8,   "Dist ",    4,MTEXT,0,PTXT,"ylabels dist",
        33,8,   "Font ",    4,MTEXT,0,PTXT,"ylabels font",
        43,8,   "Color ",   7,MTEXT,0,PTXT,"ylabels color",
        58,8,   "",     6,MSUB,102,"Ynames","ynames",
        66,8,   "Grid ",    3,MTOGOFF,SS,PTXT,"yaxis grid",

        1,10,   "",     6,MSUB,105,"X2axis","x2axis",
        16,10,  "",     6,MSUB,106,"Y2axis","y2axis",
        31,10,  "",     3,MSUB,108,"Bar","bar",
        46,10,  "",     4,MSUB,107,"Fill","fill",
        61,10,  "",     3,MSUB,109,"Let","let",
        70,10,  "",     6,MSUB,110,"Xtra's","xtra",

        1,12,   "Data Files",   0,MNULL,0,PTXT,"",
        23,12,  "Dn Marker    Lstyle Color Lwidth Smooth  Keytext     Err",
                                0,MNULL,0,PTXT,"",
        0,0,"",         0,MEND,0,0,""
};
int refresh_menu(struct menu_struct *m);
int menu_hilight(struct menu_struct *m);
int menu_norm(struct menu_struct *m);

/* menu's
        topmenu
                title,xtitle,ytitle min max dist on off, ticks dticks
                (2) let d = exp
                Data files
                Dn marker ,color, lwidth, lstyle, err,
        xnamesmenu
        ynamesmenu
        fillmenu
        barmenu
        axismenu's
*/
read_default(char *result, char *ques, char *dflt)
{
        char s[200];
        int r;
        strcpy(s,ques); strcat(s," ["); strcat(s,dflt); strcat(s,"] ");
        r = read_input(result,s);
        if (strlen(result)==0) strcpy(result,dflt);
        return r;
}
extern int changed;
addline(char *s)
{
        changed = true;
        vinsert(ngtxt+1,s);
}
char *mark_names[] = {
        "dot", "square", "fcircle", "club", "diamond", "triangle", "snake"
        ,"otimes", "odot", ""};

idiot_questions()
{
        char s1[80],ss1[60],ss2[60],ss[100];
        char s2[80];
        int m,i,nd,domark;

        scr_norm();
        window(1,1,80,25);
        clrscr();
        gotoxy(1,1);
/*  scr_menuval(); */

#define dflt(v1,v2,v3) if (read_default(v1,v2,v3)) goto abort_idiot

        addline("amove 0 0");
        addline("begin graph");
        wprintf("   Answer the following questions to set up a simple graph\n");
        wprintf("   (press return for defaults)\n\n");
        dflt(s1,"Width of graph in cm","24");
        dflt(s2,"Height of graph in cm","18");
        sprintf(ss,"    size %s %s",s1,s2); addline(ss);
        dflt(s1,"How many data files do you have to graph","1");
        nd = atoi(s1);
        for (i=0;i<nd; i++) {
                dflt(s1,"Name of data file","*.dat"); strcpy(s2,s1);
                if (strchr(s1,'*')!=NULL)  {
                        screen_save();
                        pick_file(s2,s1);
                        screen_restore();
                }
                sprintf(ss,"    data %s",s2); addline(ss);
        }
        dflt(s1,"Xaxis min","auto-scale");
        dflt(s2,"Xaxis max","auto-scale");
        ss1[0] = 0; ss2[0] = 0;
        if (strcmp(s1,"auto-scale")!=0) sprintf(ss1,"min %s ",s1);
        if (strcmp(s2,"auto-scale")!=0) sprintf(ss2,"max %s ",s2);
        sprintf(ss,"    xaxis %s %s ",ss1,ss2); addline(ss);

        dflt(s1,"Yaxis min","auto-scale");
        dflt(s2,"Yaxis max","auto-scale");
        ss1[0] = 0; ss2[0] = 0;
        if (strcmp(s1,"auto-scale")!=0) sprintf(ss1,"min %s ",s1);
        if (strcmp(s2,"auto-scale")!=0) sprintf(ss2,"max %s ",s2);
        sprintf(ss,"    yaxis %s %s ",ss1,ss2); addline(ss);

        dflt(s1,"How many datasets do you want to draw lines or markers for","1");
        nd = atoi(s1);
        dflt(s1,"Do you want lines drawn for these datasets","no");
        ss1[0] = 0;
        if (tolower(*s1)=='y') strcpy(ss1,"lstyle 1");
        dflt(s1,"Do you want markers drawn for these datasets","yes");
        domark = false;
        strcpy(ss2,"marker");
        if (tolower(*s1)=='y') domark=true;

        for (i=0, m=0;i<nd;i++,m++) {
                if (m>8) m=0;
                if (!domark) {strcpy(ss2,""); m=9;}
                sprintf(ss,"    d%d %s %s %s",i+1,ss1,ss2,mark_names[m]);
                addline(ss);
        }
abort_idiot:;
        addline("end graph");
}
int init_menucolor(void);
int m_gstart,m_gend,m_dontdraw;
menu()
{
        int nop=0,i,cc;
        char dd[20],dd2[6],ds[3];
        menutype *mi;

        init_menucolor();

        pmenu[0].menu = &graphmenu[0];
        pmenu[1].menu = &xnamesmenu[0];
        pmenu[2].menu = &ynamesmenu[0];
        pmenu[3].menu = &x2namesmenu[0];
        pmenu[4].menu = &y2namesmenu[0];
        pmenu[5].menu = &x2axismenu[0];
        pmenu[6].menu = &y2axismenu[0];
        pmenu[7].menu = &fillmenu[0];
        pmenu[8].menu = &barmenu[0];
        pmenu[9].menu = &letmenu[0];
        pmenu[10].menu = &xtramenu[0];

        initmenu();
        token_space();
/*  * Find begin...end graph commands */

        for (i=1;i<=ngtxt;i++) {
                strcpy(srclin,(*gtxt)[i]);
                token(srclin,(TOKENS) tk,&ntk,outbuff);

#if (defined EMXOS2 || defined DJ)                              /* a.r. */
        /* quick hack a.r., prevents crash if F9 pressed before Fwhatever */
                if (tk[1] == '\0')  {tk[1] = tk[2] = "Grrrr!";}
#endif
                if (strcmp(tk[1],"BEGIN")==0  && strcmp(tk[2],"GRAPH")==0)
                        nop++;
        }

/*  * Ask user which graph to edit  1...n */
        {
        pmenutype ask;
        menutype *m;
        char bb[20];
                ask.ci = 0;
                ask.menu = myallocn(1,sizeof(menutype)*10);
                m = ask.menu;
                for (i=0;i<=nop;i++,m++) {
                        sprintf(bb,"Graph %d",i+1);
                        setmenu(m,10,6+(i*2),MRETURN,0,0,"",bb,"gle loadgraph");
                        if (i==nop) m->val = sdup("Add/Create new Graph");
                        m->width = strlen(m->val);
                }
                setmenu(m,2,1,MNULL,0,0
                        ,"Select the graph in your file which you want to change (1=first graph)"
                        ,"","gle loadgraph");
                m++;
                setmenu(m,2,22,MNULL,0,0
                        ,"Use ^Z (Control+Z) to exit from each form"
                        ,"","gle loadgraph");
                if (do_menu(&ask)) return;
                i = ask.ci;
                myfree(ask.menu);
        }

        m_gstart = ngtxt+1;
        m_gend = ngtxt;
        if (i<nop) fillinmenu(i+1); else {
                getsize();
                idiot_questions();
                return;
        }
        do_menu(&pmenu[0]);
        extractmenu();
        clrscr();
}
/*

        Getkey/command
                arrowkeys normal
                left and right arrow if editing
                delete
                insert normal character
                enter, change to new menu
                escape exit.
                F1, help key
*/
char mbuff[255];

extern int iserr;
int hcx,cx,hcy; /* HIlighted current x,y */
do_menu(pmenutype *ppmenu)
{
        menutype *cm,*cmi,*si=NULL,*mi;
        int citem,emode=false;
        int c;
        cm = ppmenu->menu;
        citem = ppmenu->ci;
        cmi = cm+citem;
        refresh_menu(cm);
        menu_hilight(cmi);
        for (;;) {
         c = text_inkey();
         if (iserr) {fner_clear(); window(1,1,80,24);}
         switch (c) {
           case eescape: /* ESCAPE */
           case equit: /* control c */
                return true;
           case eleft: /* left */
                if (emode) {
                        if (cx>0) cx--;
                        gotoxy(hcx+cx,hcy);
                } else {
                        for (si=NULL,mi=cm;mi->typ!=0;mi++) {
                                if (mi->y==cmi->y && mi->x < cmi->x)
                                if (si!=NULL) {
                                        if (mi->x > si->x)
                                                si = mi;
                                } else si = mi;
                        }
                }
                break;
           case eright: /* right */
                if (emode) {
                        if (cx < strlen(cmi->val)) cx++;
                        gotoxy(hcx+cx,hcy);
                } else {
                        for (si=NULL,mi=cm;mi->typ!=0;mi++) {
                                if (mi->y==cmi->y && mi->x > cmi->x)
                                if (si!=NULL) {
                                        if (mi->x < si->x)
                                                si = mi;
                                } else si = mi;

                        }
                }
                break;
           case eup: /* arrow up */
                emode = false;
                for (si=NULL,mi=cm;mi->typ!=0;mi++) {
                        if (mi->typ<MNULL) {
                         if (si!=NULL) if (mi->y==si->y)
                           if (abs(mi->x - cmi->x) <  abs(si->x - cmi->x))
                                si = mi;
                         if (mi->y < cmi->y) if (si!=NULL) {
                           if (mi->y > si->y) si = mi;
                         } else   si = mi;
                        }
                }
                break;
           case edown: /* arrow down */
                emode = false;
                for (si=NULL,mi=cm;mi->typ!=0;mi++) {
                        if (mi->typ<MNULL) {
                         if (si!=NULL) if (mi->y==si->y)
                           if (abs(mi->x - cmi->x) <  abs(si->x - cmi->x))
                                si = mi;
                         if (mi->y > cmi->y) if (si!=NULL) {
                           if (mi->y < si->y) si = mi;
                         } else  si = mi;
                        }
                }
                break;
          case ehelp: /* f1 help */
                do_help(cmi->help);
                refresh_menu(cm);
                menu_hilight(cmi);
                break;
          case ereturn: /* carriage return */
                if (emode==true && cmi->typ==MFILE) {
                        emode = false;
                        break;
                }
                emode = false;
doreturn:;
                switch (cmi->typ) {
                  case MTEXT:
/*          if (emode) emode = false; else emode = true; */
                        break;
                  case MTOGON:
                        cmi->typ = MTOGOFF;
                        menu_hilight(cmi);
                        break;
                  case MTOGOFF:
                        cmi->typ = MTOGON;
                        menu_hilight(cmi);
                        break;
                  case MRETURN:
                        goto exit_menu;
                  case MFILE:
                        if (mystrlen(cmi->val)==0) cmi->val = myalloc(20);
                        pick_file(cmi->val,"*.dat");
                        refresh_menu(cm);
                        menu_hilight(cmi);
                        break;
                  case MSUB: /* SUB MENU */
                        if (cmi->typ2>99) do_menu(&pmenu[cmi->typ2 - 100]);
                        refresh_menu(cm);
                        menu_hilight(cmi);
                }

                for (si=NULL,mi=cm;mi->typ!=0;mi++) {
                        if (mi->y==cmi->y && mi->x > cmi->x)
                        if (si!=NULL) {
                                if (mi->x < si->x)
                                        si = mi;
                        } else si = mi;
                }

                break;
          case edelete: /* delete */
                emode = true;
                if (cmi->val==NULL) break;
                if (strlen(cmi->val)==0) break;
                if (cx<1) break;
                ncpy(mbuff,cmi->val,cx-1);
                strcat(mbuff,cmi->val + cx);
                setvstr(&cmi->val,mbuff);
                cx--;
                gotoxy(hcx+cx,hcy);
                cputs(cmi->val + cx);
                putch(DASHCHAR);
                gotoxy(hcx+cx,hcy);
                break;
          case edrawit:
                if (m_dontdraw)  break;
                extractmenu();
                window(1,1,79,24);
                scr_grey();
                clrscr();
                gotoxy(1,1);
               #ifndef EMXOS2                           /* a.r. */
                gle_redraw();
               #else
                g_get_type(devtype);
                if (strstr(devtype, "HARDCOPY") == NULL)
                       {
                        if ( oldSession != 0 ) 
                                stopPMSession(oldSession);
                        text_saveOS2tmp();
                        oldSession = startPMSession();
                       }
                else
                        gle_redraw();
               #endif
                refresh_menu(cm);
                menu_hilight(cmi);
                break;
          case eshowerror:
                text_showerror();
                refresh_menu(cm);
                menu_hilight(cmi);
                break;
          case esave: /* save file */
                extractmenu();
                text_save();
                break;
          default: /* normal key */
                if (c<26  && c!=9) {fner("Key has no affect"); break;}
                if (c>200)  fner("Unimplemented command");
                else {
/*  if (cmi->typ!=MTEXT  && cmi->typ!=MFILE) goto doreturn; */
                        emode = true;
                        if (cmi->val==NULL) setvstr(&cmi->val,"");
                        ncpy(mbuff,cmi->val,cx);
                        mbuff[cx] = c; mbuff[cx+1] = 0;
                        strcat(mbuff,cmi->val + cx);
                        setvstr(&cmi->val,mbuff);
                        gotoxy(hcx+cx,hcy);
                        cputs(cmi->val + cx);
                        cx++;
                        gotoxy(hcx+cx,hcy);
                }
                break;
         }
         if (si!=NULL) {
                menu_norm(cmi);
                cmi = si;
                menu_hilight(cmi);
                si = NULL;
         }
        }
exit_menu:;
        /* save current point */
        { int i;
                for (i=0,mi=cm;mi->typ!=0;mi++,i++) {
                  if (mi==cmi) ppmenu->ci = i;
                }
        }
        return false; /* normal exit */
}
setvstr(char **d, char *s)
{
        if ((*d) != 0) myfree(*d);
        *d = sdup(s);
}
int mystrlen(char *s)
{
        if (s==NULL) return 0;
        else return strlen(s);
}
menu_hilight(struct menu_struct *mm)
{
        int i,j;
        struct menu_struct *m=mm;
        scr_menuhi();
        hcx = m->x + mystrlen(m->title);
        hcy = m->y;
        gotoxy(hcx,hcy);
        if (m->typ==MTOGON || m->typ==MTOGOFF) {
                if (m->val==NULL) m->val = myalloc(4);
                if (m->typ==MTOGON) strcpy(m->val,"ON ");
                if (m->typ==MTOGOFF) strcpy(m->val,"OFF");
        }
        if (m->val==NULL) setvstr(&m->val,"");
        cputs(m->val);
        j = m->width - mystrlen(m->val);
        printdash(j);
        cx = mystrlen(m->val);
        gotoxy(hcx+cx,hcy);
}
printdash(int j)
{
        int i;
        for (i=0;i<j;i++) mbuff[i] = DASHCHAR;
        mbuff[j] = 0;
        if (j>0) cputs(mbuff);
}
menu_norm(struct menu_struct *mm)
{
        int i,j;
        struct menu_struct *m=mm;
        gotoxy(m->x + mystrlen(m->title),m->y);
        if (m->typ==MTOGON  || m->typ==MTOGOFF) {
                if (m->val==NULL) m->val = myalloc(4);
                if (m->typ==MTOGON) strcpy(m->val,"ON ");
                if (m->typ==MTOGOFF) strcpy(m->val,"OFF");
        }
        if (m->val != NULL) {
                scr_menuval();
                if (m->width>0) cputs(m->val);
                scr_menubg();
        }
        j = m->width - mystrlen(m->val);
        printdash(j);
}
refresh_menu(struct menu_struct *mm)
{
        int i;
        struct menu_struct *m=mm;
        window(1,1,80,24);
        scr_menubg();
        clrscr();
        for (;m->typ!=0;m++) {
                if (m->title != NULL) if (strlen(m->title)>0) {
                        gotoxy(m->x,m->y);
                        cputs(m->title);
                }
                menu_norm(m);
        }
}
extern char *tk[500];
extern char inbuff[300];
extern char tkbuff[500];
extern char space_str[3];
extern int ntk;

do_help(char *hstr)
{
        char ss[90];
        strcpy(ss,"gle graph ");
        strcat(ss,hstr);
        do_help2(ss);
}
int fread_str(char *hbuff,int count, FILE *hidx);
int fread_str(char *hbuff,int count, FILE *hidx)
{
        int i,slen;
        hbuff[0] = 0;
        i = fread(&slen,sizeof(slen),1,hidx);
        if (i<=0) return i;
        i = fread(hbuff,1,slen,hidx);
        hbuff[slen] = 0;
        return i;
}
do_help2(char *h)
{
        FILE *hfile,*hidx;
        int32 hpnt,fipnt;
        int i,yy,cp,match,capture;
        char hbuff[91],mstr[90],mstr2[90],fk1[91];
        char hstr[91],*s,*ss,hstr2[91];
        char *hfilename="graph.hlp";
        char subtopic[2000];
        int atend;

        window(1,1,80,24);
        strcpy(hstr,h);

        gotoxy(1,1);    scr_menuval();
        clreol(); wprintf("   Working..."); scr_refresh();
        hfile = fopen(gledir(hfilename),"r");
        if (hfile==NULL) {perror("Unable to open graph.hlp "); return;}
        hidx = fopen(gledir("graph.idx"),"rb");
        if (hidx==NULL) {perror("Unable to open graph.idx "); return;}
help_again:;
        rewind(hidx);
        gotoxy(1,1);    scr_menuval();
        clreol(); wprintf("   Working..."); scr_refresh();
        subtopic[0] = 0;
        strcpy(hstr2,hstr); token_data(hstr2,tk,&ntk,tkbuff);
        for (i=1;i<=ntk;i++) strlwr(tk[i]);

        /* clear(); */
        clrscr();

        if (ntk<2) tk[2] = "";
        if (ntk<3) tk[3] = "";
        if (*tk[2] == 'd' && strlen(tk[2])==2) tk[2] = "dn";
        if (strcmp(tk[3],"yaxis")==0) tk[3] = "xaxis";
        if (strcmp(tk[3],"y2axis")==0) tk[3] = "xaxis";
        if (strcmp(tk[3],"x2axis")==0) tk[3] = "xaxis";
        if (strcmp(tk[3],"ylabels")==0) tk[3] = "xlabels";
        if (strcmp(tk[3],"y2labels")==0) {tk[3] = "xlabels"; tk[2] = "off";}
        if (strcmp(tk[3],"x2labels")==0) {tk[3] = "xlabels"; tk[2] = "off";}
        if (strcmp(tk[3],"ynames")==0) tk[3] = "xnames";
        if (strcmp(tk[3],"y2names")==0) tk[3] = "xnames";
        if (strcmp(tk[3],"x2names")==0) tk[3] = "xnames";
        if (strcmp(tk[3],"ytitle")==0) tk[3] = "xtitle";
        if (strcmp(tk[3],"y2title")==0) tk[3] = "xtitle";
        if (strcmp(tk[3],"x2title")==0) tk[3] = "xtitle";
        if (strcmp(tk[3],"title")==0) tk[3] = "xtitle";

        gotoxy(1,1); wprintf("GLE help ");
        for (i=1;i<=ntk;i++) wprintf("{%s} ",tk[i]);
        scr_menubg();

        /* Find match for each key word, display that section of file
        and find rest of key words at that level */

        match = 1; /* trying to match a level one word */
        capture = false;
        for (;!feof(hidx);) {
          if (fread_str(hbuff,90,hidx)!=0) {
                fread(&fipnt,sizeof(fipnt),1,hidx);
                sprintf(mstr,"%d",match);
                sprintf(mstr2,"%d",match-1);
                if (match>ntk) {
                  strcpy(fk1,hbuff); fk1[1] = 0;
                  i = atoi(fk1);
                  if (i>0 && i<match) { /* End of section */
                        goto got_help;
                  }
                  if (i>0 && i==match) { /* Sub topic */
                        capture = false;
                        strtok(hbuff," \t\n");
                        strcat(subtopic,strtok(NULL," \t\n"));
                        strcat(subtopic," ");
                  }
                } else if (strncmp(hbuff,mstr,1)==0) { /* correct level */
                        strtok(hbuff," \t\n");
                        s = strtok(NULL," \t\n"); strcpy(fk1,s);
                        strlwr(fk1);
                        if (strncmp(fk1,tk[match],strlen(tk[match]))==0) {
                                match++;
                                if (match>ntk) {
                                        hpnt = fipnt;
                                        capture = true;
                                }
                        }
                }
          }
        }
        scr_menuval();
        gotoxy(1,9);
        wprintf("Help text not found, press any key to continue ??? \n");
        if (text_inkey()==eescape) goto quit_help;
        strcpy(hstr,"gle");
        goto help_again;

got_help:;
        cp = 1;
next_page:
        atend = help_show(hfile,hpnt,subtopic,cp);

        scr_menuval();
        gotoxy(1,23);
        if (subtopic[0]==0) s = "Enter '-' to go up a level ";
        else s = "Subtopic ";
        strcpy(mstr,s);
        if (!atend) strcat(mstr,"[next page] ");
        else strcat(mstr,"[press return to exit help] ");
        i = read_command(hbuff,mstr);
        window(1,1,80,24);
        if (i==epageup) {
                cp -=16;
                if (cp<0) cp = 0;
                goto next_page;
        }
        if (i==epagedown) {
                cp +=16;
                if (cp<0) cp = 0;
                goto next_page;
        }
        scr_menubg();
        strupr(hbuff);
        if (hbuff[0]=='-') {
                strcpy(hstr2,hstr);
                s = strtok(hstr2," \t");
                for (;s!=NULL;) {ss = s; s = strtok(NULL," \t");}
                *strstr(hstr,ss) = 0;
                goto help_again;
        }
        if (strlen(hbuff)!=0) {
                strcat(hstr," ");
                strcat(hstr,hbuff);
                goto help_again;
        }
        if (!atend) {cp+=16; goto next_page;}

quit_help:;
        fclose(hfile);
        fclose(hidx);
}
int help_show(FILE *hfile, int32 hpnt, char *st, int cp)
{
        int i=1,sl=3;
        int lvl= -1;
        char hbuff[100],*s;
        char subtopic[2000];

        strcpy(subtopic,st);
        fseek(hfile,hpnt,SEEK_SET);
        window(1,1,80,24);
        clrscr();
        scr_menuval();
        gotoxy(1,1); wprintf("GLE help ");
        for (i=1;i<=ntk;i++) wprintf("{%s} ",tk[i]);
        scr_menubg();
        for (;!feof(hfile) && sl<18;) {
          if (fgets(hbuff,90,hfile)!=NULL) {
                lvl = hbuff[0]-'0';
                if (lvl>0 && lvl<9) goto end_section;
                if (i>cp) {
                        gotoxy(1,sl++); cputs(tabtospace(hbuff));
                }
                i++;
          }
        }
end_section:
        if (strlen(subtopic)==0) goto skip_sub;

        sl++;
        gotoxy(1,sl++); cputs("Subtopics:");

        s = strtok(subtopic," \t\n");
        for (i=1;s!=NULL;i++) {
          if (i==1) strcpy(hbuff,"\t");
          if (strcmp(s,"(end)")!=0) {
                strcat(hbuff,s); strcat(hbuff,"\t");
                if (strlen(s)>7) i++;
                if (i>6) {
                        gotoxy(1,sl++); cputs(tabtospace(hbuff));
                        hbuff[0] = 0;
                        i = 0;
                        if (sl>21) return false;
                }
          }
          s = strtok(NULL," \t\n");
        }
        gotoxy(1,sl++); cputs(tabtospace(hbuff));
skip_sub:;
        if (!(lvl>0 && lvl<9) ) return false;
        return true; /* not finished */
}
add_unrecognized(char *s)
{
        if (nunrec>6) return;
        xtramenu[nunrec++].val = sdup(s);
}
int vunquote(char **s);
vunquote(char **ss)
{
        char *s = *ss;
        if (*s=='\"') {
                s[strlen(s)-1] = 0;
                *ss = sdup(s+1);
                myfree(s);
        }
}

int initmenudone;
menutype *m_pnt[20];
menutype *m_end[20];
char *m_val[20];
char m_tog[50];
initmenu()
{
        menutype *mi;
        char *s,kw1[80],kw2[80];
        int i,j,nt=0,k,z,ct,used;
        static int nv;

        if (!initmenudone) {
          minit_extras();
          initmenudone = true;
          for (z=0;z<=10;z++) {
                for (mi=pmenu[z].menu; mi->typ!=0; mi++) {
                if (mi->typ==MTOGON || mi->typ==MTOGOFF) {
                        m_tog[nt++] = mi->typ;
                }
                if (mi->val!=NULL) {
                        m_val[nv] = sdup(mi->val);
                        mi->val = sdup(mi->val);
                        m_pnt[nv++] = mi;
                }
                }
          }
        } else {
          for (z=0;z<=10;z++) {
                for (mi=pmenu[z].menu; mi->typ!=0; mi++) {
                if (mi->typ==MTOGON || mi->typ==MTOGOFF) {
                        mi->typ = m_tog[nt++];
                } else {
                        if (mi->val!=0) {
                                myfree(mi->val);
                        }
                        mi->val = 0;
                }
                }
          }
          for (z=0;z<nv;z++) {
                mi = m_pnt[z];
                mi->val = sdup(m_val[z]);
          }
        }
}

minit_extras()
{
        char dd[29],dd2[9],ds[9];
        menutype *mi;
        int i;

        i = 0;
        for (mi=graphmenu;mi->typ!=0;mi++) i++;
        for (i=0;i<9;i++) {
          setmenu(mi,2,13+i,MFILE,SROL,20,"",0,"data");mi++;
        }
        for (i=0;i<9;i++) {
         sprintf(ds,"d%d ",i);
         if (i==0) strcpy(ds,"dn ");
         sprintf(dd,"%smarker",ds); setmenu(mi,23,13+i,MTEXT,0,10,ds,0,dd); mi++;
         sprintf(dd,"%slstyle",ds); setmenu(mi,37,13+i,MTEXT,0,4,"",0,dd); mi++;
         sprintf(dd,"%scolor",ds);  setmenu(mi,42,13+i,MTEXT,0,7,"",0,dd); mi++;
         sprintf(dd,"%slwidth",ds); setmenu(mi,50,13+i,MTEXT,0,4,"",0,dd); mi++;
         sprintf(dd,"%ssmooth",ds); setmenu(mi,56,13+i,MTOGOFF,SS,3,"",0,dd); mi++;
         sprintf(dd,"%skey",ds);    setmenu(mi,60,13+i,MTEXT,SSTR,15,"",0,dd); mi++;
         sprintf(dd,"%serr",ds);    setmenu(mi,76,13+i,MTEXT,0,3,"",0,dd); mi++;
         sprintf(dd,"%serrup",ds);  setmenu(mi,78,13+i,MTEXT,0,0,"",0,dd); mi++;
         sprintf(dd,"%serrdown",ds); setmenu(mi,78,13+i,MTEXT,0,0,"",0,dd); mi++;
         sprintf(dd,"%smsize",ds); setmenu(mi,78,13+i,MTEXT,0,0,"",0,dd); mi++;
         sprintf(dd,"%smscale",ds); setmenu(mi,78,13+i,MTEXT,0,0,"",0,dd); mi++;
         sprintf(dd,"%serrwidth",ds); setmenu(mi,78,13+i,MTEXT,0,0,"",0,dd); mi++;
        }
}
char msend[200];
#define mss msend+strlen(msend)
char cs[80]="xyz";
int gstartend;
extractmenu()
{
        menutype *mi;
        char *s,kw1[80],kw2[80];
        int i,j,k,z,ct,used;

        if ((m_gstart==0) && (m_gend==0)) return;
        gstartend = m_gstart;
        for (i=gstartend;i<=m_gend;i++) vdelete(gstartend);

        if (graphmenu[2].val!=NULL) {
          if (strcmp(graphmenu[2].val,"")!=0) {
                sprintf(msend,"amove %s %s ",graphmenu[2].val,graphmenu[3].val);
                m_sendline();
          }
        }
        sprintf(msend,"begin graph ");
        m_sendline();
        for (z=0;z<=10;z++) {
          for (mi=pmenu[z].menu; mi->typ!=0; mi++) {
                if (mi->typ < MSUB  && mi->val!=NULL) {
                 if (strcmp(mi->val,"")!=0) {
                  ncpy(kw1,mi->help,strcspn(mi->help," "));
                  strcpy(kw2,"");
                  if (strlen(kw1)<strlen(mi->help))
                strcpy(kw2,mi->help + strlen(kw1) + 1);
                  switch (mi->typ2) {
                case SSIZE:
                        m_sendline();
                        sprintf(msend,"\tsize %s %s ",mi->val,(mi+1)->val);
                        mi++;
                        m_sendline();
                        break;
                case SNOBOX:
                        if (mi->typ==MTOGOFF) {
                                m_sendline();
                                sprintf(msend,"\tnobox ");
                                m_sendline();
                        }
                        break;
                case SNEXTS:
                        m_sendline();
                        strcpy(cs,kw1);
                        sprintf(mss,"\t%s \"%s\" ",kw1,mi->val);
                        break;
                case SROL:
                        m_sendline();
                        if (strcmp(kw1,"xtra")==0) {
                                sprintf(mss,"\t%s",mi->val);
                        } else {
                                sprintf(mss,"\t%s %s",kw1,mi->val);
                        }
                        break;
                case SSTR:
                        m_ifsend(kw1);
                        sprintf(mss,"%s \"%s\" ",kw2,mi->val);
                        break;
                case SNORM:
                        /* printf("ifsend cs={%s} k1={%s} {%s} \n",cs,kw1,kw2);*/
                        m_ifsend(kw1);
                        sprintf(mss,"%s %s ",kw2,mi->val);
                        break;
                case STOG:
                case SS:
                        if (mi->typ==MTOGON) {
                                m_ifsend(kw1);
                                sprintf(mss,"%s ",kw2);
                        }
                        break;
                case SSOFF:
                        if (mi->typ==MTOGOFF) {
                                m_ifsend(kw1);
                                sprintf(mss,"%s ",kw2);
                        }
                        break;
                case SAMOVE:
                        break;
                  }
                }
           }
          }
        }
        m_sendline();
        sprintf(msend,"end graph");
        m_sendline();
        m_gend = gstartend-1;
}
/* char msend[200]; */
m_sendline()
{
        if (strlen(msend)>0) vinsert(gstartend++,msend);
        msend[0] = 0;
        strcpy(cs,"xyz");
}
m_ifsend(char *s)
{
        if (strcmp(s,cs)!=0) {
          m_sendline();
          sprintf(msend,"\t%s ",s);
          strcpy(cs,s);
        }
}
int g_get_usersize(double *x, double *y);
getsize()
{
        static char s1[29], s2[29];
        double x,y;
/*  g_get_usersize(&x,&y);*/
        x = 24; y = 18;
        if (x==0) return;
        sprintf(s1,"%g",x); sprintf(s2,"%g",y);
        graphmenu[0].val = sdup(s1);
        graphmenu[1].val = sdup(s2);
}
fillinmenu(int nbegin)
{
        menutype *mi;
        char *s,kw[80],mkw[80];
        int aa,i,j,k,z,nmatch=0,ct,nop=0,used,gotit;
        menutype *match[200];
        m_gstart = 0;
        nunrec = 0;
/* for each line, compare first word on line to all first words, */
        for (i=1;i<=ngtxt;i++) {
                strcpy(srclin,(*gtxt)[i]);
                token(srclin,(TOKENS) tk,&ntk,outbuff);
                if (strcmp(tk[1],"AMOVE")==0) {
                        m_gstart = i;
                        graphmenu[2].val = sdup(tk[2]);
                        graphmenu[3].val = sdup(tk[3]);
                }
                if (strcmp(tk[1],"BEGIN")==0  && strcmp(tk[2],"GRAPH")==0) {
                        nop++;
                        if (nop==nbegin) break;
                }
        }
        if ((m_gstart+1 !=i)  || (m_gstart==0))   m_gstart = i;

        pmenu[0].menu = graphmenu;

        for (i++;i<=ngtxt;i++) {
                strcpy(srclin,(*gtxt)[i]);
                token(srclin,(TOKENS) tk,&ntk,outbuff);
                gotit = false;
                ct = 2;
                strcpy(kw,tk[1]);
                strlwr(kw);
                used = false;
                nmatch = 0;
                if (strcmp(tk[1],"END")==0) break;
                for (z=0;z<10;z++) {
                for (mi=pmenu[z].menu; mi->typ!=0; mi++) {
                  j = strlen(tk[1]);
                  if (ntk<1) if (strchr(srclin,'!')!=NULL) {
                          if (*srclin == '\t') aa=1; else aa=0;
                          add_unrecognized(srclin+aa);
                          ct = ntk + 1;
                          gotit = true;
                          goto next_xinline;
                  }
                  ct = 2;
                  if (j>1)  if (strncmp(kw,mi->help,j)==0) {
                        switch (mi->typ2) {
                          case STOG:
                          case SSTR:
                          case SSOFF:
                          case SS:
                          case SNORM: /* Just remember this one for later */
                        match[nmatch++] = mi;
                        used=true;
                        break;
                          case SNOBOX:
                        mi->typ = MTOGOFF;
                        used = true;
                        break;
                          case SSIZE:
                        mi->val = sdup(tk[2]);
                        (++mi)->val = sdup(tk[3]);
                        used = true; ct = ntk+1;
                        goto next_xinline;
                        break;
                          case SROL: /* e.g. let, bar, fill,xnames,xplaces */
                        if (mystrlen(mi->val)!=0) break;
                        k = strspn(srclin," \t");
                        k = k + strcspn(srclin+k," \t");
                        k = k + strspn(srclin+k," \t");
                        mi->val = sdup(srclin+k);
                        used=true;
                        ct = ntk+1;
                        goto next_xinline;
                          case SNEXTS: /* E.G. TITLE "XXX" ... or bar d1,d2 ...*/
                        mi->val = sdup(tk[2]);
                        vunquote(&mi->val);
                        ct = 3; used=true;
                        break;
                          case SSNULL:
                        break;
                        }
                  }
                }
                }
next_xinline:;
                if (used==false && !gotit) {
                  wprintf("Warning, unrecognized graph command {%s}\n"
                                        ,tk[1]);
                  gotit = true;
                  if (*srclin == '\t') aa=1; else aa=0;
                  add_unrecognized(srclin+aa);
                }
                used = true;
                for (j=ct;j<=ntk;j++) {
                  used = false;
                  strcpy(kw,tk[j]);
                  strlwr(kw);
                  for (k=0;k<nmatch;k++) {
                        mi = match[k];
/* gprint("match {%s} {%s}  {%s} \n",kw,mi->help,srclin); */
                        switch (mi->typ2) {
                          case STOG:
                        if (strcmp(kw,"on")==0) {mi->typ = MTOGON; used=true;}
                        if (strcmp(kw,"off")==0) {mi->typ = MTOGOFF; used=true;}
                        break;
                          default:
                        strcpy(mkw,mi->help);
                        s = strtok(mkw," "); s = strtok(0," ");
                        if (s!=NULL) if (strcmp(s,"lstyle")==0)
                          if (strcmp(kw,"line")==0) {mi->val = sdup("1"); used=true;}
                        if (s!=NULL) if (strcmp(s,kw)==0) {
                                if (mi->typ2 == SS || mi->typ2 == SSOFF) {
                                        mi->typ = MTOGON;
                                        if (mi->typ2==SSOFF) mi->typ = MTOGOFF;
                                        used = true;
                                } else {
                                 used = true;
                                 mi->val = sdup(tk[j+1]);
                                 j++;
                                 vunquote(&mi->val);
                                }
                        }
                        }
                  }
                  /*      if (used==false && !gotit) {
                          if (*srclin == '\t') aa=1; else aa=0;
                          add_unrecognized(srclin+aa);
                          wprintf("\n lost command {%s} \n",tk[j]);
                          gotit = true;
                          wprintf("Press a key\n"); text_inkey();
                  }*/
                }
        }
        m_gend = i;
/*  * Rad in graph commands, for each initial key word
                compare to all menu keywords and if match is RESTOFLINE
                type then (set item to occupied )
                and copy rest of line into value part of menu.
                else add to list of matches:
                for each word in rest of line compare to each
                matched item, and if match then put in menu value.
                (if first keyword not found then add too not
                understood list to be written out at end)
                (if second word not matched then print warning message)
*/
}
setmenu(menutype *m,int x, int y, int typ, int typ2, int width, char *title
, char *val, char *help)
{
        m->x = x; m->y = y; m->typ = typ; m->typ2 = typ2; m->width = width;
        m->title = sdup(title);
        if (val!=0) m->val = sdup(val);
        m->help = sdup(help);
}
init_menucolor()
{
                h_bcolor = WHITE; h_fcolor = BLACK;
}
static int saveplace;
int pick_file(char *result, char *wld)
{
        pmenutype ask;
        char wild[80];
        char buff2[80];
        char *f[80];
        char *swap;
        menutype *m,*mi,*mwild;
#ifndef EMXOS2                                  /* a.r. */
        struct ffblk ffblk;
#else
        HDIR            hdir;
        FILEFINDBUF3    FFbufr;
        unsigned long   SearchCnt;
#endif
        int done,i,x,y,nf,rval,adddir=false;

        strcpy(wild,wld);
        ask.ci = saveplace;
pick_again:;
        x=0; y=0; nf=0;
        init_menucolor();
#ifndef EMXOS2                                  /* a.r. */
        done = findfirst(wild,&ffblk,0);
        for (nf=0;nf<70 && !done;nf++) {
                f[nf] = sdup(ffblk.ff_name);
                done = findnext(&ffblk);
        }
#else
        SearchCnt = 1; 
        hdir = HDIR_SYSTEM; 
        done = DosFindFirst(    wild,
                                &hdir,
                                0,
                                &FFbufr,
                                sizeof(FFbufr),
                                &SearchCnt,
                                FIL_STANDARD);
        for (nf=0;nf<70 && !done;nf++) {
                f[nf] = sdup(FFbufr.achName);
                done = DosFindNext( hdir,
                                    &FFbufr,
                                    sizeof(FFbufr),
                                    &SearchCnt);
                }
#endif
sortagain:;
        swap = NULL;
        for (i=0;i<(nf-1);i++) {
                if (strcmp(f[i],f[i+1])>0) {
                        swap = f[i]; f[i] = f[i+1]; f[i+1] = swap;
                }
        }
        if (swap != NULL) goto sortagain;

        m = myallocn(3+nf,sizeof(*m));
        ask.menu = m;
        ask.ci = saveplace;
        if (saveplace>nf) ask.ci = 0;
        if (nf==0) ask.ci = 1;
        if (m==0) wprintf("memory allocation error");
        for (mi=m,i=0;i<nf;i++,mi++) {
                setmenu(mi,x*20+1,y+5,MRETURN,0,18,"",f[i],"");
                x++;
                if (x==4) {x=0; y++; }
        }
        setmenu(mi,5,1,MNULL,0,0,"Use arrow keys to select file then press return","","");
        mi++;
        setmenu(mi,5,3,MRETURN,0,30,"Disk/Dir Specification ",wild,"");
        mwild = mi;
        mi++; mi->typ = 0;
        m_dontdraw = true;
        rval = do_menu(&ask);
        saveplace = ask.ci;
        m_dontdraw = false;
        strcpy(result,((ask.menu)[ask.ci]).val);
        for (i=0;i<nf;i++) myfree(f[i]);
        myfree(m);

        if (strcmp(wild,mwild->val)!=0) {
                strcpy(wild,mwild->val);
                if (strstr(wild,"*")==NULL) {
                        if (wild[strlen(wild)-1] == '\\')
                                strcat(wild,"*.gle");
                        else
                                strcat(wild,"\\*.gle");
                }
                adddir = true;
                goto pick_again;
        }

        if (adddir) {
                *(strfile(wild)) = 0;
#if (defined __TURBOC__ || defined DJ)
                if (strstr(wild,":")!=NULL || strlen(wild)==1) {
                        setdisk(toupper(*wild)-'A');
                        if (strlen(wild)>1)
                                {strcpy(buff2,wild+2); strcpy(wild,buff2);}
                }
#endif
#ifdef EMXOS2                                                    /* a.r. */
                if (strstr(wild,":")!=NULL || strlen(wild)==1) {
                        DosSetDefaultDisk(toupper(*wild)-'A' + 1);
                        if (strlen(wild)>1)
                                {strcpy(buff2,wild+2); strcpy(wild,buff2);}
                }
                if (strlen(wild)!=1) if (_chdir2(wild)!=0) {perror("Cannot change dir"); delay(3000);}
#else
                if (strlen(wild)!=1) if (chdir(wild)!=0) {perror("Cannot change dir"); delay(3000);}
#endif
        }

/*  if (adddir) {
                *(strfile(wild)+1) = 0;
                strcpy(result,wild);
                strcat(result,((ask.menu)[ask.ci]).val);
        }
*/
        return rval;
}
char *strfile(char *s)
{
        char *e;
        e = s;
        for (;*s!=0;s++) {
                if (*s==']'  ||  *s=='\\' || *s=='/' || *s==':') e = s;
        }
        return e;
}
