/* {(rm mdl ; cc -DUNIX -I. -s -n -O -Wc,-Nd4000 -Wc,-Ns4000 -Wc,-Nt50000 -DSYSV -DNLS16 -Dhp9000s300 -o mdl mdl.c mdllib.o -lXm -lXt -lX11 -lPW ; mdl test.mdl)& } */
/**---------------------------------------------------------------------
***	
***   file:      mdl.c
***
***   project:   Menu Description Language
***                     General purpose Menu generator.
***
***         (c) 1990 Rainer Kowallik
***
***-------------------------------------------------------------------*/

#include <stdio.h>

#define TMPDIRFILE "ram:mdltmpdir.tmp"

#ifdef AMIGA
#include <exec/types.h>
#include <exec/types.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <intuition/intuition.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <workbench/icon.h>

extern struct WBStartup *WBenchMsg;
extern struct IconBase *IconBase;
#endif

#include <mdllib.h>

char   resource[80];
char   *fn_command_str[160];
char   *var_name_str[160];
char   *var_value_str[160];
int    var_value_int[160];
char   language[80];
int    wl = -1;
int    wt = -1;

/* --------------------------------------------------------
   Special callback function for mdl, executes string in
   fn_command_str[last_gadgetid]
   -------------------------------------------------------- */
void CallBack_mdl()
{
parse(fn_command_str[last_gadgetid]);
}


void main(argc,argv)
unsigned int argc;
char *argv[];
{
int n,m,i;
FILE *stream, *tmp1;
char c,tempfile[80];
char mdlfile[80];
char s[80];
int pid;

#ifdef AMIGA
char **ToolArray, *Value;
struct DiskObject *Lock;
struct WBArg *Arg;
#endif


   strcpy(language,"ksh ");
   strcpy(mdlfile,argv[1]);


#ifdef UNIX
   pid=fork();
   if(pid!=0) exit(0); /* avoid waiting of shell */
   XtToolkitInitialize();
#endif

#ifdef AMIGA
   if(argc <= 1) {
      IconBase = (struct IconBase *) OpenLibrary("icon.library", 0L);
      Arg = WBenchMsg->sm_ArgList; Arg++;
      CurrentDir(Arg->wa_Lock);
      strcpy(mdlfile,Arg->wa_Name);
   }
#endif

   stream = fopen(mdlfile,"r");
   if(stream == NULL) {
      fprintf(stderr,"mdl: could not open command file>%s<\n",mdlfile);
      exit(0);
   }


#ifdef UNIX
                /* create resource file from supplied file if possible */
	strcpy(resource,"");
	c = fgetc(stream);
	if(c == '{') {		/* copy text enclosed in {} to TMPFILE */
	   strcpy(resource,"mdl.tmp");
	   tmp1 = fopen("/usr/lib/X11/app-defaults/mdl.tmp","w");
	   n=1;
	   while(!feof(stream)) {
	      c = fgetc(stream);
	      if(c == '{') n++;
	      if(c == '}') n--;
	      if(n == 0) break;
	      fputc(c,tmp1);
	   }
	   fclose(tmp1);
	} else {
	   ungetc(c,stream);
	}

/* open display and read resource file (if any) */

	display = XtOpenDisplay (NULL, NULL, argv[0], resource, NULL, 0,
				 &argc, argv);
	if (display == NULL) {
		XtWarning ("mdl: Can't open display, exiting...");
		exit (0);
	}
#endif

  menu_init(argv,stream);
  fclose(stream);

#ifdef AMIGA
  my_window = (struct Window *) OpenWindow( my_new_window );
  SetMenuStrip( my_window, menu_bar );
  if(my_window == NULL)
  {
    fprintf(stderr,"could not open Window\n");
    close_gfx(my_window);
    exit(0);  
  }
  fin_flg = FALSE;
  MainLoop(my_window);
#endif

#ifdef UNIX
/* dont forget to activate the last menu entry */
   add_item(-1,-1,NEW_MENU,"empty",0,0);
	XtRealizeWidget (app_shell);
	XtMainLoop ();
#endif

  exit(0);
}



/* ********************************************************************

   S T R I N G H A N D L I N G

   ******************************************************************** */

/* --------------------------------------------------
   reurns in s1 s2 from nth occurence of c up to c
   -------------------------------------------------- */

ExtractStr(s1,s2,n,c)
char s1[],s2[],c;
int n;
{
int m,i,l;
char c1;

   m=0; l=strlen(s2);
   i = 0;
   if(n > 0) {
      for(i=0;i<l;i++) {
          c1=s2[i];
          if(c1 == c) m++;
          if(m == n) break;
      }
      s1[0] = 0;
      if(c1 != c) return(-1);
      i++;
   }
   m=0;
   while(i<l) {
      c1 = s2[i++];
      if(c1 == c) break;
      s1[m++] = c1;
   }
   s1[m] = 0;
   if(strlen(s1)==0) return(-1);
   return(1);
}

/* --------------------------------------------------
   check if character is a bra '([{' or a ket ')]}'
   -------------------------------------------------- */
tstbra(c)
char c;
{
   if((c == '(') || (c == '[') || (c == '{')) return(1);
   if((c == ')') || (c == ']') || (c == '}')) return(-1);
   return(0);
}




/* --------------------------------------------------
    get parameter enclosed in brackets from file.
    any New line character will be substituted by the
    supplied character.
   -------------------------------------------------- */
fgetpar(stream,s,nl)
FILE *stream;
char nl,s[];
{
int n,m,i,cnt;
char c,bra,ket;

   n=0;
   while(n != 1) {
      if(feof(stream)) return(0);
      c = fgetc(stream);
      n = tstbra(c);
   }
   bra = c;
   if(bra == '(') {
      ket = ')';
   } else {
      ket = bra + 2;
   }
/* skip SPC and NL at start of line */
   c = 0;
   while(c < 33) c = fgetc(stream);
   ungetc(c,stream);
   n = 0; cnt = 1;
   while(!feof(stream)) {
      c = fgetc(stream);
      if(c == bra) cnt = cnt + 1;
      if(c == ket) cnt = cnt - 1;
      if(c == 10) {s[n++] = ' ' ; c = nl; }
      if(cnt == 0) break;
      s[n++] = c;
   }
   s[n] = 0; 
}

/* --------------------------------------------------
    get parameter enclosed in brackets from string.
   -------------------------------------------------- */
sgetpar(str,s,n,j)
char str[],s[];
int n,*j;
{
int m,i,l,cnt;
unsigned char c,bra,ket;

   l = strlen(str);
   i = *j;
   i = n; c=str[i];
   bra = 0; ket=' ';
   if(tstbra(c) == 1) {   
      bra = c;
      if(bra == '(') {
        ket = ')';
      } else {
        ket = bra + 2;
      }
      i = i + 1;
   }
   m = 0; cnt = 1;
   while(m < l) {
     c = str[i++];
     if(c == bra) cnt = cnt + 1;
     if(c == ket) cnt = cnt - 1;
     if((ket == ' ') && (tstbra(c) != 0)) cnt = cnt -1;
     if((ket == ' ') && (c < '0')) cnt = cnt -1;
     if(cnt <= 0) break;
     s[m++] = c;
   }
   if(tstbra(c)==-1) i++;
   s[m] = 0;
   *j = i-1;
}


/* ------------------------------------------------------
   reading file and start initializing menus
   ------------------------------------------------------ */
menu_init(argv,stream)
char *argv[];
FILE *stream;
{
int n,m,i;
int p1,p2;
int x = 200,
    y = 200,
    set_flg = 0;
char c,s[256],s1[128],s2[128],*cmd,title[80];
#ifdef UNIX
Arg args[10];
#endif
   cmd = (char *) malloc(8192);

   strcpy(title,"UNTITLED SHOULD CHANGE IT !");
   while(!feof(stream)) {         /* go through file */
      c=0;
      while(c < 33) {            /* skip NL CR SPC TAB ... */
         c = fgetc(stream);
         if(feof(stream)) {free(cmd); return(0);}
      }
      ungetc(c,stream);
      c = 33; s[0]=0; n=0;
      while((c > 32) && (c < 123)) {      /* read menu command */
         c = toupper(fgetc(stream));
         if((c == '(') || (c == '[') || (c == ' ') || (c == '{')) break;
         s[n++] = c;
      }
      ungetc(c,stream);
      s[n] = 0;
/* ----------- parse command and read following parameters ---------------- */
      if(strcmp(s,"SIZE") == 0) {      /* size of main window */
         fgetpar(stream,s,' ');
         ExtractStr(s1,s,0,',');      /* get x size */
         x = atoi(s1);
         ExtractStr(s1,s,1,',');      /* get y size */
         y = atoi(s1);
         n = ExtractStr(s1,s,2,',');      /* get y increment */
         if(n == 1) bas_y = atoi(s1);
         n = ExtractStr(s1,s,3,',');      /* get top edge */
         if(n == 1) wt = atoi(s1);
         n = ExtractStr(s1,s,4,',');      /* get left edge */
         if(n == 1) wl = atoi(s1);
         continue;
      }
      if(strcmp(s,"NAME") == 0) {      /* name of application */
         fgetpar(stream,s,' ');
         strcpy(title,s);
         continue;
      }
      if(strcmp(s,"LANGUAGE") == 0) {  /* command language for application */
         fgetpar(stream,s,' ');
         strcpy(language,s);
         continue;
      }
      if(set_flg == 0) {         /* open window */
         set_flg = 1;            /* should be done only once */
   /*   Create application shell.
   */

#ifdef AMIGA
         my_new_window = init_window(x,y,title,0,1);
         if(wl > 0)my_new_window->LeftEdge = wl;
         if(wt > 0)my_new_window->TopEdge = wt;
#endif
#ifdef UNIX
	n = 0;
	XtSetArg (args[n], XmNwidth, x);  n++;
	XtSetArg (args[n], XmNheight, y);  n++;
	app_shell = XtAppCreateShell (argv[0],resource,
				applicationShellWidgetClass, display, args, n);
	main_window = CreateApplication (app_shell);
#endif
      }
      if(strcmp(s,"NEW_MENU") == 0) {      /* new entry on menu bar */
         fgetpar(stream,s,' ');         /* get name */
         add_item(-1,-1,NEW_MENU,s,0,0);
         fn_number++;
         continue;
      }
      if(strcmp(s,"MENU") == 0) {      /* new menu item */
         fgetpar(stream,s,' ');         /* get name */
         fgetpar(stream,cmd,10);      /* get action */
         add_item(-1,-1,MENU,s,0,0);
         fn_command[fn_number] = (void *)CallBack_mdl;
         fn_command_str[fn_number] = (char *) malloc(strlen(cmd)+1);
         strcpy(fn_command_str[fn_number],cmd);
         fn_number++;
         continue;
      }
      if(strcmp(s,"RADIO") == 0) {      /* start radio box */
         add_item(-1,-1,RADIO,"radio_box",0,0);
         fn_number++;
         continue;
      }
      if(strcmp(s,"TOGGLE") == 0) {      /* toggle button */
         fgetpar(stream,s,' ');         /* get name and position */
         fgetpar(stream,cmd,10);      /* get variable name */
         ExtractStr(s1,s,0,','); x = atoi(s1);   /* get x position */
         ExtractStr(s1,s,1,','); y = atoi(s1);   /* get y position */
         ExtractStr(s1,s,2,',');       /* get name */
         add_item(x,y,TOGGLE,s1,0,0);
         var_name_str[fn_number] = (char *)malloc(strlen(cmd)+1);
         strcpy(var_name_str[fn_number],cmd);
         var_value[fn_number] = &var_value_int[fn_number];
         fn_number++;
         continue;
      }
      if(strcmp(s,"PUSH") == 0) {      /* push button */
         fgetpar(stream,s,' ');         /* get name and position */
         fgetpar(stream,cmd,10);      /* get command string */
         ExtractStr(s1,s,0,','); x = atoi(s1);   /* get x position */
         ExtractStr(s1,s,1,','); y = atoi(s1);   /* get y position */
         ExtractStr(s1,s,2,',');       /* get name */
         add_item(x,y,PUSH,s1,0,0);
         fn_command[fn_number] = (void *)CallBack_mdl;
         fn_command_str[fn_number] = (char *) malloc(strlen(cmd)+1);
         strcpy(fn_command_str[fn_number],cmd);
         fn_number++;
         continue;
      }
      if(strcmp(s,"SCALEX") == 0) {      /* scale */
         fgetpar(stream,s,' ');         /* get name and position */
         fgetpar(stream,cmd,10);      /* get variable name */
         ExtractStr(s1,s,0,','); x = atoi(s1);   /* get x position */
         ExtractStr(s1,s,1,','); y = atoi(s1);   /* get y position */
         ExtractStr(s2,s,2,',');       /* get name */
         ExtractStr(s1,s,3,','); p1 = atoi(s1); /* get minimum */
         ExtractStr(s1,s,4,','); p2 = atoi(s1); /* get maximum */
         add_item(x,y,SCALEX,s2,p1,p2);
         var_value[fn_number] = &var_value_int[fn_number];
         var_name_str[fn_number] = (char *)malloc(strlen(cmd)+1);
         strcpy(var_name_str[fn_number],cmd);
         fn_number++;
         continue;
      }
      if(strcmp(s,"SCALEY") == 0) {      /* scale */
         fgetpar(stream,s,' ');         /* get name and position */
         fgetpar(stream,cmd,10);      /* get variable name */
         ExtractStr(s1,s,0,','); x = atoi(s1);   /* get x position */
         ExtractStr(s1,s,1,','); y = atoi(s1);   /* get y position */
         ExtractStr(s2,s,2,',');       /* get name */
         ExtractStr(s1,s,3,','); p1 = atoi(s1); /* get minimum */
         ExtractStr(s1,s,4,','); p2 = atoi(s1); /* get maximum */
         add_item(x,y,SCALEY,s2,p1,p2);
         var_value[fn_number] = &var_value_int[fn_number];
         var_name_str[fn_number] = (char *)malloc(strlen(cmd)+1);
         strcpy(var_name_str[fn_number],cmd);
         fn_number++;
         continue;
      }
      if(strcmp(s,"SCALEX11") == 0) {      /* scale */
         fgetpar(stream,s,' ');         /* get name and position */
         fgetpar(stream,cmd,10);      /* get variable name */
         ExtractStr(s1,s,0,','); x = atoi(s1);   /* get x position */
         ExtractStr(s1,s,1,','); y = atoi(s1);   /* get y position */
         ExtractStr(s2,s,2,',');       /* get name */
         ExtractStr(s1,s,3,','); p1 = atoi(s1); /* get minimum */
         ExtractStr(s1,s,4,','); p2 = atoi(s1); /* get maximum */
         add_item(x,y,SCALEX11,s2,p1,p2);
         var_value[fn_number] = &var_value_int[fn_number];
         var_name_str[fn_number] = (char *)malloc(strlen(cmd)+1);
         strcpy(var_name_str[fn_number],cmd);
         fn_number++;
         continue;
      }
      if(strcmp(s,"SCALEY11") == 0) {      /* scale */
         fgetpar(stream,s,' ');         /* get name and position */
         fgetpar(stream,cmd,10);      /* get variable name */
         ExtractStr(s1,s,0,','); x = atoi(s1);   /* get x position */
         ExtractStr(s1,s,1,','); y = atoi(s1);   /* get y position */
         ExtractStr(s2,s,2,',');       /* get name */
         ExtractStr(s1,s,3,','); p1 = atoi(s1); /* get minimum */
         ExtractStr(s1,s,4,','); p2 = atoi(s1); /* get maximum */
         add_item(x,y,SCALEY11,s2,p1,p2);
         var_value[fn_number] = &var_value_int[fn_number];
         var_name_str[fn_number] = (char *)malloc(strlen(cmd)+1);
         strcpy(var_name_str[fn_number],cmd);
         fn_number++;
         continue;
      }
      if(strcmp(s,"SELECTION") == 0) {      /* selection box */
         fgetpar(stream,s,' ');         /* get name and position */
         ExtractStr(s1,s,0,10); x = atoi(s1);   /* get x position */
         ExtractStr(s1,s,1,','); y = atoi(s1);   /* get y position */
         n = 2; i = 0; s1[0] = 0;
         while(i != -1) {
            i = ExtractStr(s2,s,n++,',');    /* get name */
            if(i == 1) {
               if(s1[0] != 0) strcat(s1,",");
               strcat(s1,s2);
            }
         }
         add_item(x,y,SELECTION,s1,0,0);
         var_value_str[fn_number] = (char *)malloc(80);
         var_value[fn_number] = (int *)var_value_str[fn_number];
         fn_command[fn_number] = (void *)CallBack_mdl;
         fgetpar(stream,s2,' ');      /* get variable name */
         fgetpar(stream,cmd,10);      /* get command string */
         fn_command_str[fn_number] = (char *) malloc(strlen(cmd)+1);
         strcpy(fn_command_str[fn_number],cmd);
         var_name_str[fn_number] = (char *)malloc(strlen(s2)+1);
         strcpy(var_name_str[fn_number],s2);
         fn_number++;
         continue;
      }
      if(strcmp(s,"FILE_SELECT") == 0) {   /* selection box */
         fgetpar(stream,s,' ');         /* get name and position */
         fgetpar(stream,s2,' ');      /* get variable name */
         fgetpar(stream,cmd,10);      /* get command string */
         ExtractStr(s1,s,0,','); x = atoi(s1);   /* get x position */
         ExtractStr(s1,s,1,','); y = atoi(s1);   /* get y position */
         ExtractStr(s1,s,2,',');       /* get name */
         add_item(x,y,FILE_SELECT,s1,0,0);
         var_value_str[fn_number] = (char *)malloc(80);
         var_value[fn_number] = (int *)var_value_str[fn_number];
         fn_command[fn_number] = (void *)CallBack_mdl;
         fn_command_str[fn_number] = (char *) malloc(strlen(cmd)+1);
         strcpy(fn_command_str[fn_number],cmd);
         var_name_str[fn_number] = (char *)malloc(strlen(s2)+1);
         strcpy(var_name_str[fn_number],s2);
         fn_number++;
         continue;
      }
      if(strcmp(s,"STRING_BOX") == 0) {      /* selection box */
         fgetpar(stream,s,' ');         /* get name and position */
         ExtractStr(s1,s,0,10); x = atoi(s1);   /* get x position */
         ExtractStr(s1,s,1,','); y = atoi(s1);   /* get y position */
         n = 2; i = 0; s1[0] = 0;
         while(i != -1) {
            i = ExtractStr(s2,s,n++,',');    /* get name */
            if(i == 1) {
               if(s1[0] != 0) strcat(s1,",");
               strcat(s1,s2);
            }
         }
         add_item(x,y,STRING,s1,0,0);
         var_value_str[fn_number] = (char *)malloc(64);
         var_value[fn_number] = (int *)var_value_str[fn_number];
         fn_command[fn_number] = (void *)CallBack_mdl;
         fgetpar(stream,s2,' ');      /* get variable name */
         fn_command_str[fn_number] = (char *) malloc(strlen(cmd)+1);
         var_name_str[fn_number] = (char *)malloc(strlen(s2)+1);
         strcpy(var_name_str[fn_number],s2);
         fn_number++;
         continue;
      }
      fprintf(stderr,"mdl: unknown command >%s<\n",s);
      c = 0;
      while(c != 10) {            /* try to synchronize */
         if(feof(stream)) {free(cmd); return(0);}
         c = fgetc(stream);
      }
   }
   free(cmd);
}

/* -------------------------------------------------------------
   parse a string:
   search for any occurence of $, and try to substitute
   the variable.
   Pass the string to the ksh and read the result
   ------------------------------------------------------------- */
parse(cstr)
char cstr[];
{
int i,n,m,strptr,l;
int cnt = 0;
int flg;
char c,s[80],*str,*str2;
char execfile[80];
char bra,ket;
FILE *stream;

   str = (char *) malloc(8192); str2 = (char *) malloc(8192);
   tmpnam(s);

#ifdef AMIGA
   strcpy(execfile,"ram:"); strcat(execfile,s);
#endif

#ifdef UNIX
   strcpy(execfile,s);
#endif
   strcpy(str,cstr);
   n = 0; l = strlen(str);
   while(n < l) {
      if(str[n] == '$') {      /* search for variable substitution */
         sgetpar(str,s,n+1,&i);
         flg = 0;
         for(m = 0; m < fn_number; m++) {      /* try to find menu variable */
            if(strcmp(s,var_name_str[m]) == 0 ) {   /* variable name found ! */
               flg = 1;
               if((var_funct[m] == STRING) || 
                  (var_funct[m] == SELECTION) ||
                  (var_funct[m] == FILE_SELECT)) {
                  strcpy(s,var_value_str[m]);      /* get replacement value */
               } else {
                  sprintf(s,"%d",var_value_int[m]);
               }
               break;
            }
         }
         if(flg == 0) {       /* try to find internal function */
            if(strcmp(s,"HELP") == 0) {
               flg = 1;
               sgetpar(str,s,i,&i);
               Help(s);
               strcpy(s," ");
            }
            if(strcmp(s,"EXIT") == 0) {
#ifdef AMIGA
               close_gfx(my_window);
#endif
               exit(0);
            }
            if(strcmp(s,"STRINGBOX") == 0) {
               flg = 1;
               sgetpar(str,s,i,&i);
               StringBox(s,s);
            }
            if(strcmp(s,"FILESELECT") == 0) {
               flg = 1;
               sgetpar(str,s,i,&i);
               FileSelect(s,s);
            }
         }
         if(flg == 1) {         /* replace variable name by string */
            m = 0;
            while(i < l) str2[m++] = str[i++];
            str2[m]=0;
            c = 32; m = 0;
            while(s[m] != 0) str[n++] = s[m++];
            str[n]=0;
            strcat(str,str2); l=strlen(str);
         }
      }
      n = n + 1;
   }
/* going to execute command. Output will be directed to a help window */
   if(str[0] == '!') {
      n = 0;
      while(str[n] != 0) {str[n] = str[n+1]; n++;} ; 
      ExecIO(str);
   } else {
      stream = fopen(execfile,"w");
      fprintf(stream,"%s\n",str);
      fclose(stream);

      strcpy(str,language);
      strcat(str," ");
      strcat(str,execfile);
      ExecIO(str);
      unlink(execfile);
   }

   free(str); free(str2);
}

/* add I/O redirection to command, execute command and display output */

ExecIO(cmd)
char cmd[];
{
int i,n,m,l;
char s[80];
char str[4096];
char resultfile[80];
FILE *stream;

#ifdef AMIGA
struct FileHandle *input, *output;


   tmpnam(s); strcpy(resultfile,"ram:"); strcat(resultfile,s);

   n = 0;
   while(cmd[n] != ' ') {str[n] = cmd[n]; n++;}
   str[n] = 0;
   m = 0; l = strlen(cmd);
   while(n <= l) s[m++] = cmd[n++];
   strcat(str," >"); strcat(str,resultfile);
   strcat(str," <CON:30/30/30/30/mdl-hilf");
   strcat(str,s);
input = (struct FileHandle *) Open("nil:",MODE_OLDFILE);
output = (struct FileHandle *) Open("nil:",MODE_NEWFILE);
   Execute(str,input,output);
Close(input);
Close(output);

   stream = fopen(resultfile,"r");
   n=fread(str,1,4094,stream); str[n]=0;
   fclose(stream);
#endif

#ifdef UNIX
   tmpnam(resultfile);
   freopen(resultfile,"w",stdout);
   system(cmd);
   freopen(resultfile,"r",stdout);
   n=fread(str,1,8190,stdout); str[n]=0;
   freopen("/dev/syscon","w",stdout);
#endif

   unlink(resultfile);
   if(strcmp(str,"EXIT\n") == 0) {
#ifdef AMIGA
      close_gfx(my_window);
#endif
      strcpy(str," "); /* dummy */
      exit(0);
   }
   if(n>0) Help(str);
}

