/* XWindows Interface for DOE-MACSYMA PLOT2 package */
/* (C) Copyright 1989, Paradigm Associates Inc.
   All Rights Reserved
 */

/* This "main" program is needed in Unix environments to provide
   a main loop to dispatch on X events.
*/

#include <stdio.h>

FILE *logf = NULL;

#ifdef UNIX

#define fmore(p) ((p)->_cnt > 0)


#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>



/*
 * X11 window interface for Macsyma/Plot running under Franz Lisp
 * This runs as a separate process and is spoken to via text commands
 * over a pipe (*process inport outport).
 *
 * The commands thus far are (all in text, on a line with a newline)
 *	p x y			Draw a point
 *	l x1 y1 x2 y2		Draw a line
 *	t x y text		Put text at x,y
 *	w			Put window width/height
 *				and char width/height to stdout
 *	c			Clear
 *	b			beep the bell
 *
 * Terminates on EOF.
 *
 * Barry Shein, Boston University
   George Carrette, Paradigm Associates Inc. For XR11 and VMS.
 */

/*
 * If you can't come up with an fmore(stream) macro which returns
 * whether or not there's more in the input buffer you'd better make
 * stdin unbuffered, otherwise things will get hung when usiong a pipe
 * as input as select() won't know there's more to read already in the
 * buffer.
 */

plotx_main()
{XEvent event;
 XAnyEvent *ep;
 int dpymask, stdinmask, nfound, readfds, nfds;
 char buf[BUFSIZ];

 /*
  * We are unfortunately slave to two asynchronous channels, messages
  * from the process doing the drawing and messages from the X server.
  * We'll use select to poll both and find out who is talking.
  */
 dpymask = 1 << Wdpy->fd;
 stdinmask = 1 << fileno(stdin);
 nfds = max(Wdpy->fd,fileno(stdin)) + 1;

 /*
  * Not really necessary but maybe slightly better in term's of
  * user's perceptions. Flush all pending X server requests such
  * as window creation (it might be a while till macsyma sends something)
  */
 XFlush(Wdpy);
 for(ep = (XAnyEvent *) &event;;)
   {/*
     * Always clear the queue and anything pending as the X server might
     * bundle up multiple responses
     */
    if((QLength(Wdpy) == 0) && (XPending(Wdpy) == 0))
      {for(;;)
	 {readfds = dpymask | stdinmask;
	  if(select(nfds,&readfds,0,0,0) > 0)	/* some interrupts force ret */
	    break;}}
    else
      readfds = dpymask;

    /*
     * Handle X server request
     */
    if(readfds & dpymask)
      {XNextEvent(Wdpy,ep);
      switch(ep->type)
	{case Expose:
	   onexpose(ep);
	   break;

	 case ConfigureNotify:
	   onstructurenotify(ep);
	   break;

	 default:
	   if (errdbg == 1) fprintf(stderr,"Ignored Event %d %s\n",
				    ep->type
				    decode_event_number(ep->type));
	   break;}}
    /*
     * Handle user request
     */
    if(readfds & stdinmask)
      {
#ifdef fmore
	do {
#endif
	  if(fgets(buf,BUFSIZ,stdin) != NULL) {
	    if(logf != NULL)
	      fputs(buf,logf);
	    docommand(buf);
	  }
	  else done(0);
#ifdef fmore
	} while(fmore(stdin));
#endif
    }}}

#endif

#ifdef VMS
/* Under VMS dealing with the async nature of this application is easier */
plotx_main()
{char buf[BUFSIZ];
 plotx_force_output();
 while(fgets(buf,BUFSIZ,stdin) != NULL)
   {if(logf != NULL) fputs(buf,logf);
    docommand(buf);}
 done(1);}

#endif


done(code) int code;
{fprintf(stderr,"DONE.\n");
 exit(code);}

/*
 * Handle a user request which should be a single text line
 * with a single request.
 */

docommand(bp) register char *bp;
{int x1,y1,x2,y2;
 static char label[BUFSIZ];

 switch(*bp)
   {case 'p':
    case 'P':
      if(sscanf(bp+1,"%d %d",&x1,&y1) == 2)
	plotx_point(x1,y1);
      break;

    case 'l':
    case 'L':
      if(sscanf(bp+1,"%d %d %d %d",&x1,&y1,&x2,&y2) == 4)
	plotx_line(x1,y1,x2,y2);
      break;

    case 't':
    case 'T':
      if(sscanf(bp+1,"%d %d %[^\n]",&x1,&y1,label) == 3)
	plotx_label(x1,y1,label);
      break;

    case 'w':
    case 'W':
      printf("%d %d %d %d\n",
	     plotx_width(),
	     plotx_height(),
	     plotx_char_width(),
	     plotx_char_height());
      break;

    case 'c':
    case 'C':
      plotx_clear();
      break;

    case 'b':
    case 'B':
      plotx_bell();
      break;

      /* other commands added for use during debugging */
    case 'f':
    case 'F':
      plotx_force_output();
      break;

    case 'r':
    case 'R':
      plotx_refresh();
      break;

    default:
      break;}}

main(argc,argv)
     int argc; char **argv;
{int j,syncmode_flag,errdbg_flag;
 char *xmlog, *arg,*val, *getenv();
 xmlog = 0;
 syncmode_flag = 0;
 errdbg_flag = 0;
 for(j=1;(j + 1) <argc;j = j + 2)
   {arg = argv[j];
    val = argv[j+1];
    if (strcmp(arg,"-e") == 0) errdbg_flag = atol(val);
    else if (strcmp(arg,"-l") == 0) xmlog = val;
    else if (strcmp(arg,"-s") == 0) syncmode_flag = atol(val);
    else if (strcmp(arg,"-i") == 0)
      {if ((freopen(val,"r",stdin)) == NULL)
	 {fprintf(stderr,"could not open input %s\n",val);
	  exit(1);}}
    else if (strcmp(arg,"-o") == 0)
      {if ((freopen(val,"w",stdout)) == NULL)
	 {fprintf(stderr,"could not open output %s\n",val);
	  exit(1);}}
    else fprintf(stderr,"ignored argument and value: %s %s\n",arg,val);}

 if (errdbg_flag == 1)
   {fprintf(stderr,"In debug mode\n");
    fprintf(stderr,"Sync mode = %d\n",syncmode_flag);}

 plotx_setflags(syncmode_flag,errdbg_flag);

 if(((xmlog != NULL) || ((xmlog = getenv("XMLOG")) != NULL)) &&
    ((logf = fopen(xmlog,"w")) != NULL))
   setbuf(logf,NULL);

 /*
  * Make sure that responses back to the user
  * get flushed right out
  */

#ifndef VMS
  setlinebuf(stdout);
#ifndef fmore
  setbuf(stdin,NULL);
#endif
#endif

 if(plotx_init() == 0)
   {fprintf(stderr,"%s: COULD NOT INITIALIZE X?\n",argv[0]);
    done(1);}
 
 plotx_main();}

