#include <string.h>
#include <stdio.h>

#define SELECTKEYWORD "SELECT"

static int dbg = 0;
static int dd  = 0;

static char *sqlprogram = NULL;

static FILE * fstream = NULL; /* procfile file descriptor */

#define NM 101
#define NITEMS 2010
static int nmenus = 0;
static char *menuvname[NM];
static char *menutitle[NM];
static char *mitem[NITEMS][NM];
static int nitems[NM];
static int menutype[NM];

#define M_BUTTON   0
#define M_FIELD    1
#define M_SCROLL   2
#define M_PULLDOWN 3
#define M_RADIO    4
#define M_BUTTONSET 5

static int g_widgettypes[] =
{ M_FIELD, M_BUTTON, M_SCROLL, M_PULLDOWN, M_RADIO, M_BUTTONSET };
static char *g_widgetnames[] =
{ "FIELD", "BUTTON", "SCROLL", "PULLDOWN", "RADIO", "BUTTONSET" };
#define g_ndefwidtypes (sizeof(g_widgettypes)/sizeof(int))

#define LLEN 5000
newmenu(title, vname,type) char *title, *vname; char *type;
{
  int i,t, id;
  char mtype[50];
  /* fprintf(stderr, "NEWMENU [%s] [%s] type [%s]\n", title, vname, type);  */

  sscanf(type,"%s", mtype);
  for(t=-1, i=0;i<g_ndefwidtypes;i++) 
    if(!strcmp(mtype,g_widgetnames[i])) { t = g_widgettypes[i]; break; }

  if(t==-1) return(-1);

  menuvname[nmenus] = strdup(vname);
  menutitle[nmenus] = strdup(title);
  menutype[nmenus] = t;
  nitems[nmenus] = 0;
  id = nmenus; nmenus++;
  return(id);
}

addmenuitem(id, itemname) int id; char *itemname;
{
  int n = nitems[id];
   /* fprintf(stderr,"added [%s] ",itemname);  */
  mitem[n][id] = strdup(itemname);
  nitems[id]++;
}

makeform () {
  int a;
  char buf[LLEN];

  printf("<H1> New Mosaic-SQL interface </H1> <HR>\n");
  if (getdirective("HEADING", buf))  
	  printf("%s\n",buf);
  else
	  printf("<H1> Type-2 SQL Forms <H2>\n",buf);

  printf("<FORM>\n");
  for (a=0; a< (int) getitemcount(); a++) {
	  int itemid;
	  char type[10];
     fetchitem (a , type, &itemid);
	  if (!strcmp(type,"TEXT"))
         displaytext(itemid);
	  else if (!strcmp(type,"MENU"))
         displaymenu(itemid);
	  else if (!strcmp(type,"EXEC")) {
			getscript(itemid, buf);
         execscript (buf);
			}
	  }
  printf(" <p> <INPUT TYPE=\"submit\" VALUE=\"Doit!\"> <P>\n");
  printf("</FORM>\n");

 if (dbg)  showmenus(); 
}

/* displays the menu specified by id - index into the menu structure */
displaymenu(id) int id;
{
	  int j, maxsize;
	  printf("<p> %s ", menutitle[id]);
	 if     (menutype[id]==M_FIELD ) { /* input field */
	    printf(" <INPUT NAME=\"%s\">\n", menuvname[id]);
	 }
	 else if (menutype[id]==M_BUTTON) { /* toggle button */
	    printf("<INPUT TYPE=\"checkbox\" NAME=\"%s\" > \n", 
				 menuvname[id]);
	 }
	 else if (menutype[id]==M_BUTTONSET || menutype[id]==M_RADIO) { /* buttons */
	   for(j=0;j<nitems[id];j++) {
	     if(menutype[id]==M_BUTTONSET)
	        printf("<INPUT TYPE=\"checkbox\" NAME=\"%s\" VALUE=\"%s\"> %s\n", 
				 menuvname[id], mitem[j][id] , mitem[j][id]);
	     else if(menutype[id]==M_RADIO)
	        printf("<INPUT TYPE=\"radio\" NAME=\"%s\" VALUE=\"%s\"> %s\n", 
				 menuvname[id], mitem[j][id] , mitem[j][id]);
        }
	 }
	 else if (menutype[id]==M_SCROLL || menutype[id]==M_PULLDOWN) { /* menus */
	   maxsize  = nitems[id] -1 ; if (maxsize<2) maxsize=2;
	   if(menutype[id]==M_SCROLL)
	      printf("<SELECT NAME=\"%s\" MULTIPLE>\n", menuvname[id], maxsize);
	   else if(menutype[id]==M_PULLDOWN)
	      printf("<SELECT NAME=\"%s\">\n", menuvname[id]);
	   for(j=0;j<nitems[id];j++) {
			 if(j==0)
	    	   printf(" <OPTION SELECTED>  %s\n", mitem[j][id]);
			 else
	    	    printf(" <OPTION>  %s\n", mitem[j][id]);
	    	}
       printf("</SELECT><p>\n");
	  	}
}

showmenus() {
  int i,j;
  fprintf(stderr,"SHOWALL\n");
  for(i=0;i<nmenus;i++) {
	fprintf(stderr, "MENU title [%s] [%s][%d]\n", 
						menutitle[i],menuvname[i], menutype[i]);
	 for(j=0;j<nitems[i];j++) {
		 fprintf(stderr, "\t [%s]\n", mitem[j][i]);
		}
	}
}

/* ARGS: arg[1] = procfilename 
         arg[2-..] user inputs from form output 
			Minimally, procfilename is needed.
*/
main(ac,av) int ac; char**av; {

 int i;
 char * procfilename;

 printf("Content-type: text/html \n\n");

 /*
 printf("NEW STUFF "); fflush(stdout);
 printf("NARGS %d \n", ac); if (ac>3) { printf(" SHOULD BE 3 <p>"); }
 for(i=0;i<ac;i++) { printf("<b>%d</b> [%s]\n", i,av[i]); } printf("<p>");
 */

 if(ac<2) {
	 printf("Usage: %s procfilename user-inputs...\n",av[0]); 
	 exit(0); 
	 }
 else if(ac==2) { 
	  procfilename = av[1];
     parsefile1(procfilename);
     makeform();
     exit(0);
	  }
  else {
	 char buf[LLEN];
	 procfilename = av[1];
	 combineargs(ac,av,buf);
	 /* printf("AFTER COMBINE args is <pre><tt> [%s]</tt></pre> \n", buf); */ 
    parseinputs(buf); /* buf: "v1=n1&v2=b2&...&vx=bx", b's can be empty */

    parsefile2(procfilename);
	 mergeall();
   }
 }


 combineargs(ac,av,buf) 
 int ac;
 char *av[], *buf;
 {
    int i;

	 /* av[1] is the procfilename - skip over */
	 if(ac<3) return;
    strcpy(buf,av[2]);
	 for(i=3;i<ac;i++) {
      strcat(buf,av[i]);
		 }
 }

 /* data structure to receive user inputs - conv to name-value pairs */
#define NU 200
 static char *u_vname[NU];
 static char *u_vval[NU];
 static int  u_vspecial[NU]; /* 1 if that varname starts with "_" */
 static int  n_u = 0;


 parseinputs (inbuf) char *inbuf;
 {
	char *s, *s1=inbuf;
	char *headv, *tailv;
	int i;

	for(i=0;i<NU;i++) { /* init */
	  u_vname[i]    = u_vval[i] = NULL;
	  u_vspecial[i] = 0;
	  }

	i = 0;
	printf("<pre>");
   while(NULL!=( s = strtok(s1,"&"))) {
	   {{
		char *b1, *b2;
		b1 = strchr(s,'='); if(b1==NULL) continue;
		*b1 = '\0';
		headv = strdup(s);
		b1++;
		if(b1) tailv = strdup(b1); 
	   }}
	   if(headv[0]=='_') u_vspecial[i] = 1; 
	   u_vname[i] = strdup(headv);
	   u_vval[i]  = strdup(tailv);
	   if(dd) { printf(" <li> userinput [%s] [%s]",u_vname[i], u_vval[i]);
	             if (u_vspecial[i] ) printf(" <b> special </b>\n");
					}
	   i++;
      s1=NULL;
	   }
	n_u = i;

   printf("</pre>");
 }

/* parses only display and exec directives */
parsefile1 (filename) char *filename; 
{
 char buf[LLEN];
 char title[LLEN];
 char vname[LLEN];
 int id;

 if (NULL == (fstream= fopen(filename,"r"))) {
	 printf("parsefile1: Cannot open procfile [%s]\n", filename); 
	 exit(0);
	 }

 while( getword(buf)) {
	if (buf[0]=='#') {  /* comment - ignore */
	  flushline(); 
	  }
	else if (!strcmp(buf,"TEXT")) {
	  getline(buf);
	  id = savetext(buf);
	  registeritem ("TEXT", id);
	  }
	else if (!strcmp(buf,"HEADING")) {
	  getline(buf);
	  savedirective("HEADING", buf);
	  }
	else if (!strcmp(buf,"SHOW")) {
	  getword(vname);
	  if (dbg) fprintf(stderr,"VARIABLE [%s]\n", vname);
	  getword(buf);
	  getquotedline(title); 

	  getline(buf); 
	  id = newmenu(title,vname, buf);
	  makemenu (id, buf);
	  registeritem ("MENU", id);

	  }
	else if (!strcmp(buf,"EXEC")) {
	  getline(buf);
	  id = savescript(buf);
	  registeritem ("EXEC", id);
     }
   }
  fclose (fstream);
 }

/* will scan to last semi-colon, and truncate the rest of line */
getline(ss) char*ss;
{
	  char *sp, sbuf[LLEN];

	  ss[0] ='\0';
	  while(1) {
        if (NULL==fgets(sbuf,LLEN,fstream)) { 
			  return(0); 
			  }
	     if(sbuf[0] =='#') {
			  if(dbg) fprintf(stderr," found comment [%s]\n", sbuf);
			  continue;  /* ignore comment, get another line  */
			  }
	     sp = strrchr(sbuf,';');
	     if (sp) { /* found semicolon - concat and return  */ 
			  sp[0] = '\0'; /* chop off rest of line */
		     strcat(ss,sbuf);
		     return(1);
		     }
        /* semicolon not found, concat and get more lines */
		     strcat(ss,sbuf);
		}
}

/* look for and return the next quoted string "xxx"  */
getquotedline(ss) char*ss;
{
	  char  sbuf[LLEN], *sp = sbuf;
	  int c;

	  ss[0] ='\0';

	  while (EOF != (c = fgetc(fstream)) ) {
			if (c== '\"')  /* opening quote */
				break;
			}

	  while (EOF != (c = fgetc(fstream)) ) {

			if (c== '\"') { /* closing quote */
			   *sp++ = '\0';
				strcpy(ss,sbuf);
				return(1);
				}
			else {
			   *sp++ = c; 
			   }
         }
}

flushline() { /* throw away rst of line in input stream */
	char  sbuf[LLEN];
   fgets(sbuf,LLEN,fstream);
	}

getword(ss) char*ss;
{
char *sp;
char sbuf[LLEN];

if( EOF== fscanf(fstream,"%s",sbuf) ) return(0);

if (sp = strrchr(sbuf,';')) { *sp = '\0';  } /* remove semicolon */ 

sscanf(sbuf,"%s", ss);
return(1); 
}


/* for each item, need to remove leading and trailing blanks */ 
/* Note that mline  must have a first word of the menu type keyword */ 
makemenu (menuid, mline ) int menuid; char *mline ; {
#define PATTERN  ","

 char *s, *s1;
 char *zz = mline;

 /* skip past first word  */
  while( zz && isspace(*zz) ) { zz++; }  if (zz==NULL) return; 
  while( zz && !isspace(*zz) ) { zz++; }  if (zz==NULL) return; 

 if (dbg) fprintf(stderr,"DOIT rest ID %d[%s]\n", menuid, zz);

 if (NULL!=(s1 = strstr(zz,"EXEC"))) {
	FILE *f;
	char buf[LLEN];
	execcommand((s1+4), &f); 
	while(NULL!=fgets(buf, LLEN, f)){
	  addmenuitem(menuid, buf);
	  }
   fclose(f);
	return;
	}

 s1=zz;
 while(NULL!=( s = strtok(s1,PATTERN))) {
	chopblanks(&s);
	addmenuitem(menuid, s);
   s1=NULL;
 }

}
chopblanks(ss) char **ss;
{
  char *sp = *ss;
  int n;
  while(isspace(*sp) ) sp++;
  *ss = sp;
  
  sp = *ss;
  n = strlen(*ss);
  sp = *ss+(n-1);
  while(isspace(*sp)) { *sp = '\0'; sp--; }
	
}

/* ================================================================== */
/* list of graphic objects */
#define NOBJ 200
static int obj_ref[NOBJ]; /* actually a unique reference int */ 
static int obj_type[NOBJ]; /* t - text, m - menu, e -exec */
static int n_obj = 0;

/* rets its ordering , or -1 if error */
int registeritem(type, ref) char *type; int ref;
{
	int t , n;

   if (!strcmp(type,"TEXT")) {
		t = 't';
		}
   else if (!strcmp(type,"MENU")) {
		t = 'm';
		}
   else if (!strcmp(type,"EXEC")) {
		t = 'e';
		}
   else { return(-1); }

	n = n_obj;
	obj_ref[n]  = ref;
	obj_type[n] = t;
	n_obj++;
	return (n);
}

getitemcount() { return (n_obj); }

fetchitem (which, type, ref )
int which; /* its ordering as ret from registeritem() */
int  *ref; /* output */
char *type; /* output */
{
   *ref = obj_ref[which];
   switch (obj_type[which]) {
		case 't': strcpy(type,"TEXT"); break;
		case 'm': strcpy(type,"MENU"); break;
		case 'e': strcpy(type,"EXEC"); break;
		default : strcpy(type,"NONE"); return(0);  break;
		}
   return(1);
		
}

/* ================================================================== */
/* storage for user's scripts and executables */
#define NEX 80
static char * d_ex[NEX];
static int   n_ex  = 0;

/* rets id of script , else -1 */
int savescript(ex) char *ex;
{
  int id;
  d_ex[n_ex] = strdup ( ex );
  id = n_ex;  n_ex++; 
  return (id);
}

getscript (id, ex) int id; char *ex;
{
  strcpy(ex, d_ex[id] );
}
execscript (ex) char *ex;
{
  char tfile[500];
  char buf[LLEN];
  FILE *f;

  tmpnam(tfile);
  sprintf(buf, "%s > %s ", ex, tfile);

  system( buf );
  f = fopen(tfile,"r");
  if(f==NULL) { printf("cannot open %s \n", tfile); return; }

  while(NULL!= fgets(buf, LLEN, f)) printf("%s",buf);
  fclose(f);
}     

execcommand (ex,fhandle) char *ex; FILE **fhandle;
{
  char tfile[500];
  char buf[LLEN];
  FILE *f;


  tmpnam(tfile);
  sprintf(buf, "%s > %s ", ex, tfile);

  system( buf );
  f = fopen(tfile,"r");
  if(f==NULL) { printf("cannot open %s \n", tfile); *fhandle = NULL; return; }
  *fhandle = f;

}

/* ================================================================== */
/* storage for user's text */
#define NTXT 80
static char * d_text[NTXT];
static int   n_txt = 0;

/* rets id of text, else -1 */
int savetext(text) char *text;
{
  int id;
  d_text[n_txt] = strdup ( text);
  id = n_txt;  n_txt++; 
  return (id);
}

gettext (id, text) int id; char *text;
{
  strcpy(text, d_text[id] );
}
displaytext ( id) int id;
{
  char text[LLEN];
  gettext(id, text);
  printf("%s", text);
}

/* ================================================================== */
/* defines from DEFINE */
/* sql directives and the expansion */

/* general sql directives */
static char * d_cmd[] = { "FROMLIST", "SELECTLIST", "WHERELIST", "SORTLIST", "HEADING" };
#define NW   ( sizeof(d_cmd)/sizeof(char *) )
static char * d_mean[NW];
static int   n_cmd = NW;

/* defines from DEFINE */
#define MDEF 40
static char * d_defvar[MDEF];
static char * d_defval[MDEF];
static int n_def = 0;

/* variables from SUB */
#define NV 200
static char * var_name[NV];
static char * var_mean[NV];
static char * var_kind[NV]; /* what list it's part of eg SELECT or WHERE */
static char * var_fmt[NV]; /* string to format output as */
static int   var_used[NV]; /* 1 if has user input */
static int n_var = 0;

parsefile2 (filename) char *filename; 
{
 char buf[LLEN], tbuf[LLEN];
 char vname[LLEN];
 int id, i;

 if (NULL == (fstream= fopen(filename,"r"))) {
	 printf("parsefile2: Cannot open procfile [%s]\n", filename); 
	 exit(0);
	 }

for(i=0;i<NW;i++) {  d_mean[i] = NULL; }

for(i=0;i<NV;i++) { /* init */
  var_name[i] = var_mean[i] = var_kind[i] = NULL; 
  var_used[i] = 0;
  var_fmt[i] = NULL;
  }

 printf("<PRE>");
 while( getword(buf)) {
	if (buf[0]=='#') { 
	  if(dbg) fprintf(stderr,"comment word [%s]\n", buf);
	  flushline(); 
	}
	else if (!strcmp(buf,"HEADING")) {
	  getline(buf);
	  savedirective("HEADING", buf);
	  }
	else if (!strcmp(buf,"SUB")) {
	  getword(vname); 
	  var_name[n_var] = strdup(vname);
	  getword(buf); /* kind */
	  var_kind[n_var] = strdup(buf);
	  getword(buf); /* AS */
	  getline(buf); /* meaning */
	  var_mean[n_var] = strdup(buf);
	  if(dd) printf("<li> FILE VAR [%s] [%s] [%s] \n", 
	                var_name[n_var], var_kind[n_var], var_mean[n_var]);
	  n_var++;
	  }
	else if (!strcmp(buf,"SQLPROG")) {
		getline(tbuf);
		sqlprogram = strdup(tbuf);
		}
	else if (!strcmp(buf,"DEFINE")) {
	   getword(tbuf);
		sscanf(tbuf,"%s",buf);
	   d_defvar[n_def] = strdup(buf);
	   getline(tbuf);
		sscanf(tbuf,"%s",buf);
	   d_defval[n_def] = strdup(buf);
	   if(dd) printf("<li> usrdefine [%s] [%s]\n", d_defvar[n_def], d_defval[n_def]);
	   n_def++;
	  }
	else { /* save if is a sql directive */
	   getline(tbuf);
		savedirective (buf, tbuf);

		}
  }
 printf("</PRE>");
  fclose (fstream);
}

/* ------------------------------------------------------------------ */
/* returns the meaning of a SUB variable */
lookupmean (var, meaning) char *var, *meaning;
{
	int i;
   for (i=0;i<n_var;i++) 
		if (!strcmp(var, var_name[i])) {
		  strcpy(meaning, var_mean[i]);
		  return(1);
		  }
   return(0);		
}
/* ------------------------------------------------------------------ */
/* updates the var_xxx structures with info from user */
/* doesn't account for duplicate vars for now */

mergeall() 
{
   
	int i, j, t, num;
	char *vname;
	char buf[LLEN]; /* contains all matches (comma-separated) for a variable */
	int match[200], nm;
	char sqlstr[LLEN];

	/* -- sub user inputs in the variables --- */
	/* some vars (arrays) can have multiple userinput values */
   for (i=0;i<n_var;i++) {
		vname = var_name[i];
		for (nm=0, t=0; t<n_u; t++) {
          if (!strcmp(vname, u_vname[t])) {
				 if (strlen(u_vval[t])>0) { /* don't bother if empty value */
				   var_used[i] = 1;
				   match[nm] = t; nm++;
				   }
				 }
		    }
		if (nm>0) { /* build the match string */
			buf[0]='\0';
		   for (j=0;j<nm;j++) {
				t = match[j];
		      if (u_vspecial[t]) { /* look up its meaning */
					char tbuf[LLEN];
					if (!lookupmean (u_vval[t], tbuf)) {
						strcpy(tbuf,"Undefined"); 
						printf("<li>UNDEFINED [%s]\n", u_vval[t]);
						}
               else {
				     if (j!=0) strcat(buf, ",");
			        strcat(buf, tbuf);
			        }
			      }
            else { /* just use the input */
				   if (j!=0) strcat(buf, ",");
			      strcat(buf, u_vval[t]);
               }
            }
		   substitute(&var_mean[i], buf);
         }
	  }

  /* --- build the sql string from the pieces ---  */

	 sqlstr[0] ='\0';
	 strcat (sqlstr," \" " );
	 strcat( sqlstr, SELECTKEYWORD);

  	 num = 0;
	 if( getdirective("SELECTLIST", buf)) {
       strcat(sqlstr,  buf );
		 num = 1;
	    }
    for (i=0;i<n_var;i++) {
	    if (var_used[i]) { 
	  	    if (!strcmp(var_kind[i],"SELECTLIST")) {
				 if(num>0) strcat(sqlstr, ", ");
             strcat(sqlstr, var_mean[i]);
				 num++;
				 }
			 }
	    }
	 if (num==0) { /* yikes..no user-selected values, & no default select list */
		 printf(" <H1> You must select field(s) to display. </H1> "); 
		 return; 
		 }


	 if( getdirective("FROMLIST", buf)) {
       strcat(sqlstr, " FROM ");
       strcat(sqlstr,  buf );
		 }

	 num = 0;
    strcat(sqlstr, " WHERE ");
    for (i=0;i<n_var;i++) {
  	    if (var_used[i]) {
  		    if (!strcmp(var_kind[i],"WHERELIST")) {
				 if(num>0) strcat(sqlstr, " AND ");
             strcat(sqlstr, var_mean[i]);
				 num++;
	          }
	       }
	    }
	 if( getdirective("WHERELIST", buf)) {
       if (num>0) strcat(sqlstr, " AND  ");
       strcat(sqlstr,  buf );
	    }

	 if( getdirective("SORTLIST", buf)) {
       strcat(sqlstr,  buf );
	    }

    strcat(sqlstr, " \" "); /* entire sql string is quoted */

	 if(dd) printf("<b> SQL </b> <tt> %s </tt> <p> \n", sqlstr);

	stuffmenu("Here is the SQL Query ", sqlstr );

	strcat(sqlstr," ");
   for(i=0;i<n_def;i++) {
		 char zz[LLEN];
		 sprintf(zz," \"%s %s\" ",d_defvar[i], d_defval[i]);
		 strcat(sqlstr,zz);
		 }

  if (getdirective("HEADING", buf))  printf("%s\n",buf);
   printf("<P>");

	{{ char cmd[LLEN];
		if (sqlprogram==0) {
			printf("<H1> Sorry..I don't know what SQL program to run.");
			printf("<p>SQLPROG is not specified! </H1>");
			exit(0);
			}
		sprintf(cmd," %s %s ", sqlprogram, sqlstr);
		/* stuffmenu("Here is the cmd ", cmd); */

		fflush(stdout);
      system(cmd);
	}}

}

savedirective(cmd, meaning) 
char * cmd , *meaning;
{
   int i;

	for(i=0;i<NW;i++)  
		if (!strcmp(cmd , d_cmd[i])) {
         d_mean[i] = strdup(meaning); 
			return(1);
			break;
		}
	return(0);
}

getdirective (cmd , meaning)
char * cmd , *meaning;
{
    int i;
    for (i=0;i<n_cmd;i++) 
	    if (!strcmp(d_cmd[i], cmd)) {
			if(NULL==d_mean[i]) return (0);
			strcpy(meaning, d_mean[i]);
			return(1);
	      }
	return(0);
}


/* substitute all occurences of $ in x1 with x2 */
/* this means reallocing the string at x1 */
substitute(x1, x2) char **x1, *x2; {
	char buf[LLEN];
	char *orig = *x1;
	char *sp;

	/* printf("<p> sub [%s] inside [%s] ", x2, orig); */
	sp = strchr(orig,'$');
	if (sp==NULL) return;

	buf[0] = '\0';
   
	*sp ='\0';
   strcat(buf,orig);  /* first portion */

   strcat(buf,x2);    /* substituted portion */

   sp++;
	if(sp) {        /* end portion */
	  strcat(buf,sp);
     }

   *x1 = strdup(buf);
	/* printf("new string is [%s] ", *x1); */
}

/* stuff some text into a menu */
stuffmenu(title, string) char *title, *string;
{
       int n;
		 char *stringbuf;
		 char buf[LLEN];
		 char *ss, *s2, *s1;


		 stringbuf = strdup(string);
		 /* remove quotes */
         s1 = strchr(stringbuf,  '\"'); if(s1) *s1 = ' ';
         s1 = strrchr(stringbuf,  '\"'); if(s1) *s1 = ' ';

		 printf("<FORM>");
	    printf("<SELECT NAME=\"sql-query\">\n" );
	    printf(" <OPTION>  %s \n", title);

       s1 = ss = stringbuf;
       while(1) {
			 s2 = strchr(s1, ' ');
			 if(s2==NULL) break;
			 n = s2 - ss;
          if (n > 80) {
				strncpy(buf,ss,n); buf[n]='\0';
	    	    printf(" <OPTION>  %s\n", buf);
				ss = ++s2; if(ss==NULL) break;
				}
          else {
             s1 = s2+1;
				}

          }
		 if (ss) printf(" <OPTION>  %s\n", ss); /* trailing text */
       printf("</SELECT><p>\n");
		 printf("</FORM>");

		 fflush(stdout);
}
