/*===========================================================================
  Copyright (C) 1995-2010 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/* ++++++++++++++++++++++++++++++++++++++++++++++++++
 
.IDENTIFICATION
  helpme.c
  K. Banse		ESO - Garching	1.00	920423
 
.KEYWORDS
  help facility
 
.PURPOSE
  display help information
  holds  helpme, subj, disphlp, hlpdir, outfil, match_pattern
 
.ALGORITHM
  cumbersome but rather straight forward ...
  but do not write that into the logfile (to save space...) unless
  keyword LOG(3) is set

.VERSIONS [1.00] 980525:  pulled over from helper.c

 100921		last modif
-------------------------------------------------- */
 
#include <fileexts.h>
#include <fsydef.h>

#include <string.h>
#include <stdio.h>

#include <sys/types.h>
#include <dirent.h>

char   midver[12], munit[2];
char   midhome[84];

int  mindx, staticflag;
 
void prepmem();
int  findir(), dspout(), outfil(), subj(), disphlp(), hlpdir(), match_pattern();

/*

*/

void mySCTPUT(text)
char  *text;

{
if (staticflag == 2)
   dspout(text);
else
   (void) SCTPUT(text);
}

/*

*/

int helpme(fflg,Midver,linx,contxt,mypntr)

int   fflg;		/* IN: source = 1 (from helper.exe), = 2 (from GUI) */
char  *Midver;		/* IN: Midas unit (2 chars) + version (max 5 chars) */
char  *linx;		/* IN: Midas command line */
char  *contxt;		/* IN: list of all enabled contexts */
char  **mypntr;		/* IN: addr. of pointer to contexts */

{
int  hit, ll, ltoken;
int  mm, n, noff;
int  jstart, start, stat;
int  hflag, remem;
#if vms
int  fp, reclen;
#endif

char      token[80], comnd[20], qualif[16];
char      oline[80], line[80], hqualf[6], hcom[20];
char      errmess[80], file[80], filtyp[6];
char      savchar;

static char  *comla[7] = {"branch","crossref","do","entry",
                          "goto","if","return"};





/* if fflg = 2, get pointer to returned ASCII text if it's first time */

munit[0] = Midver[0];		/* separate Midas unit and version */
munit[1] = Midver[1];
(void) strcpy(midver,&Midver[2]);

staticflag = fflg;			/* we need this flag later on */
if (fflg == 2)
   {
   (void) strcpy(oline,"help ");		/* construct full line */
   if (*linx == '/')
      {
      (void) strcpy(&oline[4],linx);
      (void) strcat(oline," ? ");	/* provide help/qual ?  at least */
      }
   else
      (void) strcpy(&oline[5],linx);
   prepmem(mypntr);
   }
else
   (void) strcpy(oline,linx);



/*  extract HELP command + qualifier  */

errmess[0] = ' ';
hqualf[0] = ' ';
start = 0;
ltoken = CGN_EXTRSS(oline,(int)strlen(oline),' ',&start,hcom,19);
jstart = start;
CGN_UPSTR(hcom);
if ( (hcom[0] == '?') && (hcom[1] == '?') )
   hflag = 1;                             /* command/qualif ??  */
else
   {
   hflag = 0;                             /* HELP ...  */
   ll = CGN_INDEXC(hcom,'/');             /* test HELP qualifier  */
   if (ll > 0) (void) strncpy(hqualf,&hcom[ll+1],2);
   if (hqualf[0] == 'K') 
      goto sect_3000;			/* HELP/KEYWORD */
   else if (hqualf[0] == 'A')
      goto sect_6000;			/* HELP/APPLIC  */
   else if ((hqualf[0] == 'C') && (hqualf[1] == 'O'))
      goto sect_7000;			/* HELP/CONTRIB  */
   else if ((hqualf[0] == 'W') || (hqualf[0] == 'S'))
      goto sect_8000;			/* HELP/WHAT    */
}
 

/*  test, if general help  */

try_again:
ltoken = CGN_EXTRSS(oline,(int)strlen(oline),' ',&jstart,token,60);
if ( (token[0] == '?') || (token[0] == '\0') )
   {
   if (hqualf[0] == 'C') 		         /* HELP/CL  */
      {
      (void) strcpy(file,"MID_HELP:alll.mlz");
      (void) strcpy(filtyp,".mlz");
      }
   else
      {
      (void) strcpy(file,"MID_HELP:alll.hlz");
      (void) strcpy(filtyp,".hlz");
      }
   (void) strcpy(comnd,"alll");			/* this info is needed later */
   hflag = 2;
   qualif[0] = '\0';				/* so it's initialized */
   goto sect_1000;
   }


/*  look for HELP topics */

if (token[0] == '[') 
   {
   if ((token[1] == 'K') || (token[1] == 'k'))
      {
      (void) strcpy(line,"		Global System Keywords:");
      dspout(line);
      (void) strcpy(line,"      ");
      dspout(line);
      token[0] = '\0';				/* emulate HELP/KEY ? */
#if vms
      outfil("MID_MONIT:syskeys.vms","C SECT./",token);
#else
      outfil("MID_MONIT:syskeys.unix","C SECT./",token);
#endif
      return(0);
      }

   subj(token,midver,file);                          /* get full name  */
   if (file[0] != '\0')
      {
      remem = disphlp(file,hflag,comnd,qualif);
      if ((remem == 9) || (remem == 0)) return(0);
      }
   (void) sprintf(line,"%s - invalid topic entered ...",token);
   mySCTPUT(line);
   return(-1);
   }
 

/*  extract command + qualifier */

mm = CGN_INDEXC(token,'/');
if ((mm > 0) && (strncmp(&token[mm],"/..",3) == 0))
   {
   token[mm] = '\0';			/* command/...  =>  command */
   ltoken = mm;
   mm = -1;
   }

if (mm < 0) 
   {
   mm = ltoken;
   if (mm > 6) mm = 6;
   (void) strncpy(comnd,token,mm);
   comnd[mm] = '\0';                      /* command has max. 6 chars...  */
   qualif[0] = '\0';
   (void) strcpy(filtyp,".hlc");
   if (hflag != 1) hflag = 2;             /* HELP command  or  command ??  */
   }
else
   {
   (void) strcpy(line,&token[mm+1]);		  /* save the qualifier */
   if (mm > 6) mm = 6;
   (void) strncpy(comnd,token,mm);
   comnd[mm] = '\0';
   n = (int)strlen(line);
   if (n > 0)
      {
      if (n > 4) n = 4;
      CGN_LOWCOPY(qualif,line,n);
      qualif[n] = '\0';
      savchar = qualif[--n];
      while ( (savchar != '/') &&
              (savchar != '_') &&
              ((savchar < '0') || 
               (savchar > 'z') ||
               ((savchar < 'a') && (savchar > '9'))) ) 
         {
         n--;
         if (n<0) break;
         savchar = qualif[n];
         }
      if (n == 2)			/* qualif[0,1,2] only */
         {
         if (strncmp(qualif,"ima",3) == 0)
            qualif[++n] = 'g';
         else if (strncmp(qualif,"tab",3) == 0)
            qualif[++n] = 'l';
         else if (strncmp(qualif,"des",3) == 0)
            qualif[++n] = 'c';
         else if (strncmp(qualif,"key",3) == 0)
            qualif[++n] = 'w';
         else if (strncmp(qualif,"col",3) == 0)
            qualif[++n] = 'u';
         else if (strncmp(qualif,"lin",3) == 0)
            qualif[++n] = 'e';
         }
      qualif[++n] = '\0';
      }
   else
      qualif[0] = '\0';

   if (hflag != 1) 
      {
      hflag = 3;                                /* HELP command/qualif  */
      (void) strcpy(filtyp,".hlq");
      }
   else
      (void) strcpy(filtyp,".hlc");                    /* command/qualif ??  */
   }
 

/*  test for special comnd names */

if (comnd[0] == '$') 
   (void) strcpy(comnd,"vaxx");
else if (comnd[0] == '@') 
   (void) strcpy(comnd,"aaaaaa");
else if (strcmp(comnd,"help") == 0) 
   {
   if (qualif[0] == 'a')
      (void) strcpy(qualif,"appl");
   else if (qualif[0] == 'k')
      (void) strcpy(qualif,"keyw");
   else if (qualif[0] == 'i')
      (void) strcpy(qualif,"info");
   }
 
ll = (int)strlen(comnd);
if ((hflag == 3) && (ll < 6) && (qualif[0] != '\0')) 
   {
   comnd[ll++] = '_';                       /* append "_"   */
   comnd[ll] = '\0';
   }
 

/*  construct name of help file */

if (hqualf[0] != 'A') CGN_LOWSTR(comnd);

if (hqualf[0] == 'C') 		         /* HELP/CL  */
   {
   filtyp[1] = 'm';                      /* mlc  or  .mlq  */
   if (filtyp[3] == 'q')
      hflag = 3;
   else
      hflag = 2;
   for (n=0; n<7; n++)
      {
      if (CGN_INDEXS(comla[n],comnd) >= 0)
         {
         ll = (int)strlen(comla[n]);
         if (ll > 6) ll = 6;
         (void) strncpy(comnd,comla[n],ll);
         comnd[6] = '\0';
         hflag = 3;
         break;
         }
      }
   if ((strncmp(comnd,"els",3) == 0) || (strncmp(comnd,"endi",4) == 0))
      {
      memset((void *)comnd,32,(size_t)6);
      (void) strcpy(comnd,"if");
      hflag = 3;
      }
   if (strncmp(comnd,"endd",4) == 0)
      {
      (void) strcpy(comnd,"do");
      hflag = 3;
      }
   }

(void) strcpy(file,"MID_HELP:");
if (filtyp[3] == 'q') 
   {
   (void) strcat(file,comnd);
   CGN_LOWSTR(qualif);
   (void) strcat(file,qualif);
   }
else
   (void) strcat(file,comnd);
(void) strcat(file,filtyp);
   

sect_1000:						/*
----------						*/
remem = disphlp(file,hflag,comnd,qualif);
if (remem == 9) return(0);
noff = 0;
 

/*  general HELP - loop also through all enabled contexts */

if (strcmp(comnd,"alll") == 0) 
   {
   if (filtyp[1] == 'm')
      return(0);				/* already finished */

   else if (filtyp[1] == 'h') 
      {
      dspout("   ");                 /* display an empty line */
      if (staticflag == 1) 
         {
         dspout("for commands of the MIDAS Command Language use: HELP/CL comnd/qualif");
         dspout("   ");  
         }

      sect_1800:					/*
      ----------					*/
      if (contxt[noff] == ' ') 
         {
         hlpdir("applic  ",midver,file);	    /* goto ./applic/help  */
         (void) strcat(file,comnd);
         (void) strcat(file,".hlz");
         remem = disphlp(file,hflag,comnd,qualif);
         if (remem == 9) return(0);

         dspout("   "); 
         (void) strcpy(file,"MID_HELP:alll.alz");   /* display all topics */
         remem = disphlp(file,hflag,comnd,qualif);
         if (staticflag == 1) 
            {
            dspout
         (" To obtain information about these topics enter:    HELP [topic]");
            dspout
         (" the first '[' is very important - otherwise minimum match is used");
            }
         return(0);
         }
      else 
         {                                          /* look for alll.hlz  */
         hlpdir(&contxt[noff],midver,file);         /* in contexts  */
         if (*file != '\0')			    /* if !HELP = found ... */
            {
            (void) strcpy(line,"for commands from context: ");
            (void) strncpy(&line[27],&contxt[noff],8);
            line[35] = '\0';
            mySCTPUT(line);
            (void) strcat(file,"alll.hlz");
            remem = disphlp(file,hflag,comnd,qualif);
            mySCTPUT(" ");

            if (remem == 9) return(0);
            }
         noff += 8;
         goto sect_1800;
         }
      }
   }

 
/*  for "HELP command"  loop also through all enabled contexts */

if ((filtyp[3] == 'c') && (filtyp[1] != 'm'))
   {
   if (remem == 0) 
      hit = 1;
   else
      hit = 0;
  
   /*  now also look into APPLIC.HELP... */

   hlpdir("applic  ",midver,file);
   (void) strcat(file,comnd);
   (void) strcat(file,".hlc");
   remem = disphlp(file,hflag,comnd,qualif);

   if (remem == 9) return(0);

   if (remem == 0) hit++ ;                           /* something found...  */
 

   sect_2000:						/*
   ----------						*/
   if (contxt[noff] == ' ') 
      {
      if (hit > 0) 
         {
         if (hflag == 1)
            return(0);			/* for comm/qual ?? we're done  */
         mySCTPUT(" ");
         mySCTPUT("For detailed information on individual commands");
         mySCTPUT
  ("enter 'HELP command/qualif' or 'HELP command/ ' if no qualifier exists");
         }
      else
         goto last_try;
      }
   else
      {
      hlpdir(&contxt[noff],midver,file);
      if (*file != '\0')			    /* if !HELP = found ... */
         {
         (void) strcat(file,comnd);
         (void) strcat(file,".hlc");
         remem = disphlp(file,hflag,comnd,qualif);

         if (remem == 9) return(0);

         if (remem == 0) hit++ ;                      /* something found...  */
         }
      noff += 8;
      goto sect_2000;
      }
   }
 

/*  for "HELP command/qualif"  we only have to hit home once */
 
else if (remem != 0) 
   {
   hlpdir("applic",midver,file);
   (void) strcat(file,comnd);
   (void) strcat(file,qualif);
   (void) strcat(file,".hlq");
   remem = disphlp(file,hflag,comnd,qualif);

   if ((remem == 9) || (remem == 0)) return(0);         /* something found.. */
  

   sect_2500:						/*
   ----------						*/
   if (contxt[noff] != ' ') 
      {
      remem = 1;			/* set to failure */
      hlpdir(&contxt[noff],midver,file);
      if (*file != '\0')			    /* if !HELP = found ... */
         {
         (void) strcat(file,comnd);
         (void) strcat(file,qualif);
         (void) strcat(file,".hlq");
         remem = disphlp(file,hflag,comnd,qualif);
         if (remem == 9) return(0);		/* service the QUIT */
         }
      if (remem != 0)
         {
         noff += 8;
         goto sect_2500;
         }
      }
   else
      goto last_try; 				/* nothing found */

   }
return(0);

last_try: 
if (hqualf[0] != 'C') 
   {
   jstart = start;
   hqualf[0] = 'C';			/* try one more time with HELP/CL */
   goto try_again;
   }
goto sect_77000;


/* ------------------------ */
/*  handle HELP/KEY keyname */
/* ------------------------ */

sect_3000:
#if vms
(void) strcpy(file,"MID_MONIT:syskeys.vms");
#else
(void) strcpy(file,"MID_MONIT:syskeys.unix");
#endif

ltoken = CGN_EXTRSS(oline,78,' ',&jstart,token,60);
if (token[0] == '?')
   token[0] = '\0';
else
   CGN_UPSTR(token);

stat = outfil(file,"C SECT./",token);
if (stat != 0)
   {
   (void) strcpy(errmess,"invalid keyname in HELP/KEY command...");
   goto sect_78000;
   }
return(0);



/* ------------------- */
/*  handle HELP/APPLIC */
/* ------------------- */

sect_6000:
ltoken = CGN_EXTRSS(oline,80,' ',&jstart,token,60);
if (token[0] == '?')
   (void) strcpy(token,"help");
else if (strcmp(token,"compfits") == 0)
   (void) strcpy(token,"compFITS");	/* I know it's stupid, but it works */

(void) strcpy(file,"APP_PROC:");
(void) strcat(file,token);
(void) strcat(file,".prg");

stat = outfil(file,"! +","+");
if (stat != 0) 
   {
   (void) strcpy(errmess,"invalid name in HELP/APPLIC command...");
   goto sect_78000;
   }
return(0);



/* -------------------- */
/*  handle HELP/CONTRIB */
/* -------------------- */

sect_7000:
ltoken = CGN_EXTRSS(oline,80,' ',&jstart,token,60);
if (token[0] == '?')
   (void) strcpy(token,"help");
else
   CGN_LOWSTR(token);

(void) strcpy(file,"CON_PROC:");
(void) strcat(file,token);
(void) strcat(file,".prg");
stat = outfil(file,"! +","+");
if (stat != 0)
   {
   (void) strcpy(errmess,"invalid name in HELP/CONTRIB command...");
   goto sect_78000;
   }
return(0);



/* -------------------------------------------------------------- */
/*  handle HELP/SUBJECT string (look for pattern) - old HELP/WHAT */
/* -------------------------------------------------------------- */

sect_8000:

stat = 0;

for (n=jstart; n<80; n++)		/* skip leading blanks */
   {
   if (oline[n] != ' ') break;
   }

CGN_UPCOPY(token,&oline[n],40);	    /* convert to upper case for matching */


#if vms

mm = 1;
(void) strcpy(file,"MID_HELP:helpwhat.h1");
fp = CGN_OPEN(file,READ);
if (fp == -1) goto sect_77000;
 

/*  if HELP/SUBJECT ?   we want a display of all options */

if (token[0] == '?') 
   {
   mySCTPUT("Information is available for the following subjects:");
   mySCTPUT(" ");

   while (mm == 1)
      {
      reclen = osaread(fp,line,80);
      if (reclen < 0) goto subj_eof;
      if (line[0] == '>') 
         {
         mySCTPUT(line);
         mySCTPUT(" ");
         }
      }
   }
 

/*  here for the individual stuff */

n = CGN_INDEXC(token,' ');
if (n > 0) token[n] = '\0';		/* stop at first blank */

while (mm == 1)
   {
   reclen = osaread(fp,line,80);
   if (reclen < 0) 
      {
      (void) strcpy(errmess,"no matching subject pattern found... ");
      osaclose(fp);
      hqualf[0] = ' ';			/* try again with normal help */
      goto try_again;
      }
   if (line[0] == '>') 
      {
      CGN_UPCOPY(file,line,80);
      n = CGN_INDEXS(file,token);
      if (n == 1) break;			/* first match */
      if ((n > 0) && (file[n-1] == ' ')) break;
      }
   }


while (mm == 1)			/* skip over possible following '> lines' */
   {
   reclen = osaread(fp,line,80);
   if (reclen < 0) goto subj_eof;
   if (line[0] != '>') break;
   }
 

while (mm == 1)				/*  matching pattern found */
   {
   mySCTPUT(line);
   reclen = osaread(fp,line,80);
   if ((reclen < 0) || (line[0] == '>')) goto subj_eof;
   }
 

subj_eof:				/*  end-of-file */
osaclose(fp);

#else

if (token[0] == '?') 
   {
   mySCTPUT(" ");
   mySCTPUT("Enter subject you want to search for in the help data base.");
   mySCTPUT(" ");
   mySCTPUT
   ("All commands containing the chosen subject in their help are shown.");
   mySCTPUT(" ");
   mySCTPUT("If any commands are found, we switch to \"Commands\" mode");
   mySCTPUT("and you can click on any command to navigate.");
   }

else
   {
   n = CGN_INDEXC(token,' ');
   if (n > 0) token[n] = '\0';             /* stop at first blank */

   mm = match_pattern(token,"MID_HELP");
   mm += match_pattern(token,"applic");
   mm += match_pattern(token,"ccdred");
   mm += match_pattern(token,"cloud");
   mm += match_pattern(token,"daophot");
   mm += match_pattern(token,"echelle");
   mm += match_pattern(token,"feros");
   mm += match_pattern(token,"imres");
   mm += match_pattern(token,"invent");
   mm += match_pattern(token,"irspec");
   mm += match_pattern(token,"iue");
   mm += match_pattern(token,"long");
   mm += match_pattern(token,"mos");
   mm += match_pattern(token,"pepsys");
   mm += match_pattern(token,"qc");
   mm += match_pattern(token,"rbs");
   mm += match_pattern(token,"romafot");
   mm += match_pattern(token,"spec");
   mm += match_pattern(token,"statist");
   mm += match_pattern(token,"surfphot");
   mm += match_pattern(token,"tsa");
   mm += match_pattern(token,"wavelet");

   if (fflg == 2)		/* here from the Help GUI? */
      {
      if (mm > 0)
         stat = 99;
      else
         stat = -99;
      }
   }

#endif


return(stat);
 

/*  required file not found */

sect_77000:						/*
-----------						*/
if (errmess[0] == ' ')
   {
   (void) strcpy(errmess,comnd);
   (void) strcat(errmess,qualif);

   if ((strncmp(filtyp,".hlq",4)==0) && ((int)strlen(qualif)==4))
      (void) strcat(errmess," - no help file found (invalid qualifier ...)");
   else if ((strncmp(filtyp,".hlc",4)==0) && ((int)strlen(comnd)==6))
      (void) strcat(errmess," - no help file found (invalid command ...)");
   else
      (void) strcat
      (errmess," - no help file found (typing more characters might help ...)");
   }


/* help file not found for HELP/APPLIC, CONTRIB, KEYW  */

sect_78000: 
mySCTPUT(errmess);
return(-1);

}
 
/*

*/

int subj(comstr,midver,filnam)

/* ++++++++++++++++++++++++++++++++++++++++++++++++++
 
 .IDENTIFICATION
   function subj		version 1.00      900330
   K. Banse       		ESO - Garching
 .PURPOSE
   find required topic with minimum match
 .ALGORITHM
   stupid
 .INPUT/OUTPUT
   call as  subj(comstr,filnam)
          filnam[0] = '\0'   if no match
 
 .VERSIONS

  --------------------------------------------------  */
 
char   *comstr;		/* IN:  '[first_chars'   */
char   *midver;		/* IN: MIDAS version     */
char   *filnam;		/* OUT: full filename    */

{
int   ll, nn, reclen;
int  fp;
 
char     stri[8], record[88];
 

*filnam = '\0';
nn = (int) strlen(comstr);
if (nn > 7) 					/* max 6 characters are used */
   ll = 6;
else
   ll = nn - 1;
CGN_LOWCOPY(stri,&comstr[1],ll);
if (stri[ll-1] == ']')
   stri[ll-1] = '\0';
else
   stri[ll] = '\0';
  
if (strncmp(stri,"hostm",5) == 0)	/* [Host+Midas] */
   (void) strcpy(stri,"host+m");

if (strncmp(stri,"mswind",5) == 0)	/* [MS-Windows] */
   (void) strcpy(stri,"ms-win");

  
/*  open file findall.alc */

(void) strcpy(record,"MID_HELP:findall.alc");
fp = CGN_OPEN(record,READ);
if (fp == -1)
   {
   (void) strcpy(record,"Problems opening file MID_HELP:findall.alc ");
   mySCTPUT(record);
   return(-1);
   }
  
read_loop:
reclen = osaread(fp,record,20);

if (reclen > 0)
   {
   nn = CGN_INDEXS(record,stri);       /*  test, if index function hits home */
   if (nn == 0) 
      {
      nn = CGN_INDEXC(record,'\t');
      record[nn] = '\0';
      (void) strcpy(filnam,"MID_HELP:");
      (void) strcpy(&filnam[9],record);
      goto file_close;
      }
   goto read_loop;
   }  

file_close:
 osaclose(fp);
    
return 0;
}

/*

*/

int disphlp(filnam,flag,comand,qualif)

/* ++++++++++++++++++++++++++++++++++++++++++++++++++
.IDENTifICATION
  subroutine DSPHLP		version 1.00      870209
  K. Banse       		ESO - Garching
  1.10      870216                    	1.20      870703
  1.30      881010			1.40	  901217
.PURPOSE
  display MIDAS help info on the terminal
.ALGORITHM
  depending upon value of FLAG search file for desired info
.RETURN
stat:       int return status
.VERSIONS
  1.10            fix single command help (FLAG = 1)
  1.20            update to new HMA syntax
  1.30            pass also backslash char. as parameter, because it depends
                  on the FORTRAN compiler ...
  1.40            new file name conventions 
 --------------------------------------------------  */

char  *filnam;		/* IN: file name  */
int  flag;		/* IN: action flag                            \
                               0 = display general help file alll.hlc \
                               1 = short help for COMMAND/qualif      \
                               2 = general help for COMMAND           \
                               3 = detailed help for COMMAND/qualif  */
char  *comand;		/* IN: command string */
char  *qualif; 		/* IN: '/qualif'  */

{
static int reclim = 100000;
 
int    kstat, stat, l1, n, nn, nnn, reclen, try;
int    fp;
 
static char   blank[] = "    ";
 
char  mystr[88], record[88], toc[8];
 
 
 
/*  if flag = 3, qualifier should have 4 characters...  */

if ((flag == 3) && ((int)strlen(qualif) < 4)) 
   try = 1;                /* this may be a candidate for individual search  */
else
   try = 0;

  
/*  open file */

(void) strcpy(record,filnam);

sect_900:
fp = CGN_OPEN(record,READ);
if (fp == -1) goto sect_8800;

stat = 0;

 
/*  for FLAG = 1, we show one command/qualif syntax */

if (flag == 1) 
   {
   (void) strcpy(mystr,"SECTION./");
   (void) strcat(mystr,qualif);
   CGN_UPSTR(mystr);
   l1 = (int)strlen(mystr);
  
   for (n=1; n<reclim; n++)
      {
      reclen = osaread(fp,record,80);
      if (reclen < 0) goto sect_1500;
  
      record[l1] = '\0';
      if (strcmp(record,mystr) == 0)
         {
         reclen = osaread(fp,record,80);
         if (reclen < 0) goto sect_1500;
          
         kstat = dspout(record);
         if (kstat == 1) goto sect_7800;
         reclen = osaread(fp,record,80);
         if (reclen < 0) goto sect_7700;                 /* get next record  */

         if (strncmp(record,"SECTION.",8) != 0)
            {
            kstat = dspout(record);
            if (kstat == 1) goto sect_7800;
            }
         goto sect_7700;
         }
      }
 
sect_1500:
   stat = 1;                             /* we're done + have found nothing */
   }
 
 
/*  for flag = 2, we show all command/qualif options for a given command */

else if (flag == 2) 
   {
   (void) strcpy(mystr,"SECTION./");
   (void) strcat(mystr,qualif);
   CGN_UPSTR(mystr);
   l1 = (int)strlen(mystr);
  
   for (n=1; n<reclim; n++)
      {
      reclen = osaread(fp,record,80);
      if (reclen < 0) goto sect_7700;
      
      if ((reclen > 0) && (record[0] != '%'))
         {
         if (strncmp(record,"SECTION.",8) != 0)
            {
            kstat = dspout(record);
            if (kstat == 1) goto sect_7800;
            }
         }
      }
   }

 
/*  HELP  command/qualif */

else if (flag == 3) 
   {
   (void) strcpy(toc,"\\es");
   for (n=1; n<reclim; n++)
      {
      reclen = osaread(fp,record,80);
      if (reclen < 0) goto sect_7700;
      if (strncmp(record,toc,3) == 0)
         {
         reclen = osaread(fp,record,80);
         if (reclen < 0) goto sect_7700;
         kstat = dspout(record);
         if (kstat == 1) goto sect_7800;
         kstat = dspout(blank);
         if (kstat == 1) goto sect_7800;

         for (nn=0; nn<reclim; nn++)
            {
            reclen = osaread(fp,record,80);
            if (reclen < 0) goto sect_7700;
            if (strncmp(record,"Pur",3) == 0)
               {
               kstat = dspout(record);
               if (kstat == 1) goto sect_7800;
               for (nnn=1; nnn<reclim; nnn++)
                  {
                  reclen = osaread(fp,record,80);
                  if (reclen < 0) goto sect_7700;
                  kstat = dspout(record);
                  if (kstat == 1) goto sect_7800;
                  }
               }
            }
         }
      }
   } 

/*  all other options  */

else
   {
   for (n=0; n<reclim; n++)
      {
      reclen = osaread(fp,record,80);
      if (reclen < 0) goto sect_7700;
      if ( (record[0] != '\\') && (record[0] != '%') )
         {
         kstat = dspout(record);
         if (kstat == 1) goto sect_7800;
         }
      }
   }
 

/*  close file + return */

sect_7700:
(void) osaclose(fp);
return stat;

sect_7800:
(void) osaclose(fp);
stat = 9;				/* indicate the `quit'  */
return stat;


/*  problems with file opening ...
  for wild card commands we don't get complete qualifier
  so we have to search for it in the corresponding command.hlc file */

sect_8800:
if (fp != -1) (void) osaclose(fp);

if (try == 1) 
   {
   try = 0;                               /* first of all reset it  */
   l1 = (int)strlen(comand);

   findir(mystr,filnam);
   (void) strcat(mystr,comand);

   if (comand[l1-1] == '_') 
      {
      l1 = (int)strlen(mystr) - 1;
      mystr[l1] = '\0';
      }

   (void) strcat(mystr,".hlc");

   fp = CGN_OPEN(mystr,READ);
   if (fp == -1) goto sect_8800;

   (void) strcpy(mystr,"SECTION./");
   (void) strcat(mystr,qualif);
   CGN_UPSTR(mystr);
   l1 = (int)strlen(mystr);
  
   for (n=0; n<reclim; n++)
      {                                  /* pull out 4 char. qualifier...  */
      reclen = osaread(fp,record,80);
      if (reclen < 0) 
         {
         osaclose(fp);
         goto stat_2;
         }

      if (strncmp(record,mystr,l1) == 0)
         {
         CGN_LOWSTR(record);
         findir(mystr,filnam);
         (void) strcat(mystr,comand);
         l1 = (int)strlen(mystr);
         (void) strncpy(&mystr[l1],&record[9],4);
         (void) strcpy(&mystr[l1+4],".hlq");
         (void) strcpy(record,mystr);
         osaclose(fp);
         goto sect_900;				/* try again ...  */
         }
      }
   }
 
stat_2:
stat = 2;
return stat;

}

/*

*/

int hlpdir(contxt,midver,direc)

char  *contxt;		/* IN: context name (exactly 8 chars...)  */
char  *midver;		/* IN: MIDAS version    */
char  *direc;		/* OUT: help directory  */

{
int  mm, ll, reclen;
int  fp;
 
char   frame[80], record[104], mycntxt[12];
  
static char  *fix_name[] = {"applic", "stdred", "contrib"};


*direc = '\0';			/* set to no success */


memset((void *)mycntxt,32,(size_t)10);
(void) strncpy(mycntxt,contxt,8);
ll = CGN_INDEXC(mycntxt,' ');
mycntxt[ll] = '\0';


/* prepare midhome such, to hold MidasHome/MidasVersion (if Unix) */

#if vms							/* VMS */
   (void) strcpy(midhome,"MID_DISK:[");
   OSY_GETSYMB("MIDASHOME",frame,40);
   mindx = CGN_INDEXC(frame,' ');
   frame[mindx++] = '.';
   (void) strcpy(&frame[mindx],midver);
   CGN_strcpy(&midhome[10],midhome);
#else							/* Unix */
   (void) OSY_TRNLOG("MIDASHOME",midhome,80,&mm);
   midhome[mm++] = FSY_DIREND;
   (void) strcpy(&midhome[mm],midver);
#endif



if (strcmp(mycntxt,"applic") == 0)
   {
   (void) strcpy(direc,midhome);
#if vms                                               /*  VMS  */
   (void) strcat(direc,".APPLIC.HELP]");
#else                                                 /*  Unix  */
   (void) strcat(direc,"/applic/help/");
#endif
   return(0);
   }
  


/*  first look for file FORGRxx.CTX in MID_WORK  */

(void) strcpy(frame,"MID_WORK:FORGR  .CTX");
frame[14] = munit[0];
frame[15] = munit[1];

fp = CGN_OPEN(frame,READ);
if (fp != -1)
   {
  read_it:
   reclen = osaread(fp,record,100);   
   if (reclen < 0)
      (void) osaclose(fp);			/* context not found */
   else if (strncmp(record,contxt,8) == 0)
      {						/* we found the context */
      (void) strcpy(frame,&record[8]);		/* extract its directory */
      (void) osaclose(fp);
      goto see_more;
      }
   else
      goto read_it;				/* loop more  */
   }


/*  look for context file in MID_CONTEXT, default dir or MID_WORK  */

(void) strcpy(frame,"MID_CONTEXT:");

see_more:
(void) strcat(frame,mycntxt);
(void) strcat(frame,".ctx");

fp = CGN_OPEN(frame,READ);
if (fp == -1) 
   {			/* not found in MID_CONTEXT, so try in default dir. */
   (void) strcpy(frame,mycntxt);
   (void) strcat(frame,".ctx");
   fp = CGN_OPEN(frame,READ);
   if (fp == -1) 
      {			/* not found here, so try in MID_WORK */
      (void) strcpy(frame,"MID_WORK:");
      (void) strcat(frame,mycntxt);
      (void) strcat(frame,".ctx");
      fp = CGN_OPEN(frame,READ);
      if (fp == -1) return(0);
      }
   }


/*  read the file + look for !HELP = ... */

read_file:
reclen = osaread(fp,record,80);   
if (reclen < 0) goto close_file;
    

if (strncmp(record,"!HELP = ",8) != 0)
   goto read_file;                                     /* loop more  */
   
ll = 8;
while(record[ll] == ' ') 
   {
   ll ++;
   if (ll >= 79) goto close_file;
   }
       
CGN_strcpy(record,&record[ll]);
for (ll=(int)strlen(record)-1; ll > 4; ll--)
   {
   if (record[ll] != ' ')
      {
      record[ll+1] = '\0';
      break;
      }
   }


/* we have stored the directory in `record'
   check, if its's one of the MIDAS subdirs  */

(void) strcpy(frame,record);		/* save string first */
CGN_LOWSTR(record);			/* make sure we have lowercase dir  */

for (ll=0; ll<3; ll++)
   {
   if (strcmp(fix_name[ll],record) == 0) 
      goto sect_1500;
   }


#if vms
(void) strcpy(direc,frame);		/* use original string */
 
#else
(void) strcpy(direc,midhome);
 
if (strncmp(record,"$midashome/$midvers/",20) == 0)
   {
   (void) strcat(direc,&frame[19]);
   (void) strcat(direc,"/");
   }
else if (strncmp(record,"$mid_home/",10) == 0)
   {
   (void) OSY_TRNLOG("MID_HOME",direc,80,&mm);
   (void) strcat(direc,&frame[9]);
   (void) strcat(direc,"/");
   }
else if (strncmp(record,"$pipe_home/",11) == 0)
   {
   (void) OSY_TRNLOG("PIPE_HOME",direc,80,&mm);
   (void) strcat(direc,&frame[10]);
   (void) strcat(direc,"/");
   }
else
   {
   (void) strcpy(direc,frame);		/* use original string */
   ll = (int)strlen(direc);
   if (direc[ll-1] != FSY_DIREND)
      {
      direc[ll++] = FSY_DIREND;
      direc[ll] = '\0';
      }
   }
#endif

goto close_file; 			/* we take the string as it is */
 

/*  build up complete directory name */

sect_1500:
(void) strcpy(direc,midhome);

#if vms                                         /*  VMS  */
   (void) strcat(direc,".");
   (void) strcat(direc,record);
   (void) strcat(direc,".");
   (void) strcat(direc,mycntxt);
   (void) strcat(direc,".HELP]");
#else                                           /*  Unix  */
   (void) strcat(direc,"/");
   (void) strcat(direc,record);
   (void) strcat(direc,"/");
   (void) strcat(direc,mycntxt);
   (void) strcat(direc,"/help/");
#endif
 

/* that's the end of it */

close_file:

osaclose(fp);
return(0);
}

/*

*/

int outfil(file,prefix,label)

/*++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  display part of a file
.ALGORITHM
  look for prefix//label
  the display until prefix//... is encountered
  if prefix = '\0', display everything
  if label = '\0', use prefix to turn display on + off alternatively
.RETURN
  stat:	I*4	= 0, if ok, else -1
--------------------------------------------------*/
 
char   *file; 	  /* IN : file name  */
char   *prefix;   /* IN : prefix string */
char   *label;	  /* IN : label string  */
 
{
int   stat, reclen;
int  jmm, jkk, comp_flg;
int  fp;
 
char	compo[20], record[88];
 
 
/*  open file */
 
fp = CGN_OPEN(file,0);			/*  open for read  */
if (fp == -1) return (-1);
 
jkk = -1;
jmm = (int)strlen(prefix);
if (jmm == 0)
   comp_flg = 0;
else
   {
   (void) strcpy(compo,prefix);
   jkk = (int)strlen(label);
   if (jkk > 0) 
      {
      comp_flg = 1;
      (void) strcat(compo,label);
      }
   else
      comp_flg = 2;
   jkk += jmm;		/* length of search string  */
   }
 
 
read_loop:
 
reclen = osaread(fp,record,80);
 
if (reclen == 0)
   goto read_loop;
else if (reclen == -1)
   {
   osaclose(fp);
   if (comp_flg == 1)
      return (-1);
   else
      return (0);
   }
else if (record[reclen-1] == 13)
   reclen --;
 
 
if (comp_flg == 0)
   {
   stat = dspout(record);
   if (stat == 1) goto end_of_it;
   goto read_loop;
   }


if (strncmp(record,compo,jkk) == 0) 
   {

inner_loop:
   reclen = osaread(fp,record,80);
   if (reclen < 0) goto end_of_it;
 
   if (reclen == 0) goto inner_loop;

   if (strncmp(record,prefix,jmm) == 0)
      {
      if (comp_flg == 1)
         goto end_of_it;
      else
         {
         dspout("   ");			/* display an empty line */
         goto read_loop;		/* turn display off */
         }
      }
   else
      {
      stat = dspout(record);
      if (stat == 1) goto end_of_it;
      goto inner_loop;
      }
   }
 
else
   goto read_loop;
 
end_of_it:
 osaclose(fp);
 return (0);
}

/*

*/

int findir(s,sn)
char *s, *sn;

{
int pos, i;


(void) strcpy(s,sn);
 
i = (int)strlen(s)-1; 

while (s[i] != ':' && s[i] != '/' && s[i] != ']') i--;

pos = i+1;
s[pos] = '\0';
return(pos);
}

/*

*/

int match_pattern(patt,context)
char  *patt, *context;

{
int  n, k, ctxflag, nofiles, reclen, realo, fp, found;

char  realcont[12], direc[88], ctxmess[20];
char  oslname[168],  realname[168], line[88], Upline[88];
char  topictable[168];

struct dirent  *dirp, *oslread();


if (strcmp(context,"MID_HELP") == 0)
   {
   ctxflag = -1;
   (void) strcpy(direc,context);
   }
else if (strcmp(context,"applic") == 0)
   {
   ctxflag = 0;
   hlpdir("applic  ",midver,direc);
   }
else
   {
   ctxflag = 1;
   memset((void *)realcont,32,(size_t)8);
   n = (int) strlen(context);
   (void) strncpy(realcont,context,n);
   realcont[8] = '\0';
   hlpdir(realcont,midver,direc);
   (void) sprintf(ctxmess,"\tin context: %s",realcont);
   }


(void) OSY_TRNLOG(direc,realname,140,&realo);
if (realname[realo-1] != FSY_DIREND) realname[realo++] = FSY_DIREND;
realname[realo] = '\0';

if (ctxflag == -1)
   {					/* get Topic translation table */
   (void) strcpy(topictable,realname);
   (void) strcat(topictable,"findall.alc");
   }


found = 0;
(void) strcpy(oslname,realname);
(void) strcpy(direc,"*.hlq");		/* type of help files to look for */

do_it:
nofiles = oslopen(oslname,direc);
if (nofiles < 0) 
   {
   if (direc[2] == 'h')
      return 0;
   else
      return found;
   }


while (nofiles > 0)
   {
   nofiles --;

   dirp = oslread();
   (void) strcpy(&realname[realo],dirp->d_name);    /* get file name */

   fp = osaopen(realname,READ);
   if (fp > -1)
      {

     read_loop:
      memset((void *)line,32,(size_t)80);
      reclen = osaread(fp,line,80);
      if (reclen > 0) 
         {
         CGN_UPCOPY(Upline,line,80);
         n = CGN_INDEXS(Upline,patt);
         if (n > -1)				/* we have a match */
            {
            if ((ctxflag == -1) && (direc[2] == 'a'))
               {
               (void) osaclose(fp);
               n = CGN_JNDEXC(realname,FSY_DIREND);
               if (n > 0) CGN_strcpy(realname,&realname[n+1]);
               fp = osaopen(topictable,READ);
               if (fp < 0)
                  (void) sprintf(line,"topic [%s]",realname);
               else
                  {
                  (void) strcpy(line,"Topic not found...");
                 topic_loop:
                  k = osaread(fp,line,60);
                  if (k > 0)
                     {
                     n = CGN_INDEXS(line,realname);
                     if (n == 0)
                        {
                        n = CGN_INDEXC(line,'[');
                        (void) sprintf(line,"topic %s",&line[n]);
                        goto file_close;
                        }
                     goto topic_loop;
                     } 
 
                  file_close:
                  (void) osaclose(fp);
                  }
 
               mySCTPUT(line);
               found = 1;

               goto get_next;
               }

            (void) osaclose(fp);
            fp = osaopen(realname,READ);	/* poor man's rewind */

           reread_loop:
            reclen = osaread(fp,line,80);
            if (reclen > 0) 
               {
               if (strncmp(line,"\\es\\co",6) == 0)
                  {
                  reclen = osaread(fp,line,80);
                  if (reclen > 0) 
                     {
                     for (k=0; k<reclen; k++)
                        {
                        if ((line[k] == ' ') || (line[k] == '\t'))
                           {
                           line[k] = '\0';
                           break;
                           }
                        }
                     if (ctxflag == 1)
                        (void) strcat(line,ctxmess);
                     mySCTPUT(line);
                     found = 1;
                     }

                  (void) osaclose(fp);
                  goto get_next;
                  }
               goto reread_loop;
               }
            (void) osaclose(fp);
            }

         else
            goto read_loop;
         }
      (void) osaclose(fp);
      }
   get_next:
   ;
   }

(void) oslclose();

if (ctxflag == -1)			/* only in main help */
   {
   if (direc[2] == 'h')
      {					/* look also for .alq files */
      (void) strcpy(direc,"*.alq");
      goto do_it;
      }
   }

return (found);
}

