/*===========================================================================
  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
===========================================================================*/

/*++++++++++++++++++++ MIDAS monitor routines PREPF +++++++++++++++++++++++++++
.LANGUAGE  C
.IDENTIFICATION Module PREPF
.AUTHOR  K. Banse                  ESO - Garching
.KEYWORDS
  MIDAS command data structures
.COMMENTS
  holds INITCOM, EXTRACOM, FINDCOM, ADDCOM, MINMATCH, DELCOM, cut_links,
        SETDFF, CLEANCOM, PACKCOM, MODOFF, DEFCOM, SHOWCOM, spitout
.VERSION   [1.00] 871030:  debugging ...

 100608		last modif
----------------------------------------------------------------------------*/
 
#include <fileexts.h>
#include <commext.h>
#include <monitdef.h>
#include <midback.h>

#include <stdio.h>
#include <stdlib.h>



static struct COMND_STRUCT   *compntr, *cnext;
static struct QUALIF_STRUCT  *qualpntr, *qnext, *qlast;

/*

*/

static int MINMATCH(stra,strb,maxlen)

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  compare two strings and consider minimum_match problems
.ALGORITHM
  usual comparison but blanks are considered like wild cards
.RETURNS
  0, if strings are different
  1, if strings are completely equal
  2, if strings are ambiguous, i.e. are equal until the first blank
-----------------------------------------------------------------*/
char    *stra           /* IN: 1. input string (not terminated by \0) */;
char    *strb           /* IN: 2. input string (not terminated by \0) */;
int maxlen              /* IN: max. length of strings */;

{
register int  nr;

register char ca, cb;




for (nr=0; nr<maxlen; nr++)
   {
   ca = stra[nr];
   cb = strb[nr];

   if (ca == cb) continue;              /* we don't stop at the first blanks */
                                        /* but loop till maxlen anyway */

   if ( ((ca == ' ') || (cb == ' ')) && (nr > 0) )
      return(2);                                /* ambiguous */

   return(0);                                   /* really different */
   }

return (1);                                     /* really equal */

}
/*

*/

/* ***						*** */
/* here the section for command completion in Midas */
/* ***						*** */

#ifndef NO_READLINE

struct COMMAND {
  char name[12];                /* User printable name of the function */
  struct COMMAND *prev;
  };

struct CMD_LIST {
  struct COMMAND *curr;
  struct COMMAND *last;
  };

struct CMD_LIST cmds = {
   (struct COMMAND *)NULL,
   (struct COMMAND *)NULL
   };



void free_cmd_list()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  Free the memory allocated for the Command/Qualifier list.
  Also executed with the BYE command.
.RETURNS
  nothing
-----------------------------------------------------------------*/
{
  struct COMMAND *mycmd;

  while ((mycmd = cmds.last)) {
    cmds.last = mycmd->prev;
    free((char *)mycmd);
    }
}



void update_cmd_list()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  Update the Command/Qualifier list used for completeness with GNU 
  readline
.RETURNS
  nothing
-----------------------------------------------------------------*/
{
int list_cmd;
register int  m, n;

struct COMND_STRUCT *compntr;
struct QUALIF_STRUCT *qualpntr;
struct COMMAND *mycmd;




MONIT.CMD_LIST_UPDA = 0;		/* reset the flag */
free_cmd_list();			/* Free previous list */


/* Initialize static list of commands */

compntr = COMN.CP;
qualpntr = COMN.QP + compntr->INDX;
list_cmd = 0;
while (list_cmd <= COMN.INUSEC) 
   {
   if (compntr->STR[0] != '\\')
      { 
      while (1)
         {
         mycmd = (struct COMMAND *)malloc((size_t)(sizeof(struct COMMAND)));
         (void) memset((void *)mycmd->name,32,(size_t)12);	/* space-fill */
         mycmd->prev = cmds.last;
         cmds.last = mycmd;
         (void) memcpy(mycmd->name,compntr->STR,(size_t)6);
         if (qualpntr->STR[0] != ' ') 
            {
            m = 6;			/* get rid of trailing blanks */
            for (n=5; n>0; n--)
               {
               if (mycmd->name[n] != ' ')
                  {
                  m = n+1;
                  goto done;
                  }
               }
           done:
            mycmd->name[m++] = '/';
            (void) memcpy(&mycmd->name[m],qualpntr->STR,(size_t)4);
            mycmd->name[11] = '\0';
            }
         else
            mycmd->name[6] = '\0';
         if (qualpntr->NEXT == -1) break;
         qualpntr = COMN.QP + qualpntr->NEXT;
         }
      }
   list_cmd++;
   compntr++;
   qualpntr = COMN.QP + compntr->INDX;
   }

cmds.curr = cmds.last;
}

#endif
/*

*/
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  read in the binary file newcom.bin
  which contains all fixed MIDAS commands and qualifiers
.ALGORITHM
  use FSY_OPNFIL to read the file
.RETURNS  status (0 = o.k., 1 = bad)
------------------------------------------------------------------*/
 
int INITCOM()

{
int   mm, nn, stat;
int   totsize, comsize, qualsize;
int   cmax, qmax, lmax;
	
unsigned int  linesize;

char    *cpntr, *tmpntr;

int  fp;

static int   initflag = -1;

static char  file[] = "MID_MONIT:newcom.bin";
static char  record[200];
	
 
 
/*  if initflag != -1, we clean up virtual memory from last call */

if (++initflag > 0)
   {
   free((char *)COMN.CP);
   free((char *)COMN.QP);
   free(COMN.LINE);
   }


/*  open + read the command/qualif stuff from binary file newcom.bin      */
 
CGN_LOGNAM(file,record,200);       /* translate name */
fp = osdopen(record,READ);
if (fp == -1)
   {
   (void) printf("Problems with initial command file %s - %s\n",
                  record,osmsg());
   return(1);
   }
 

/*  and read it to get the sizes of the following structures */

cpntr = (char *) &COMN;
totsize = sizeof(struct COMND_ALL);

stat = osdread(fp,cpntr,(unsigned int)totsize);
if (stat < totsize) goto osd_error;


/*  save the original sizes from file (needed for reading correct amounts)  */

cmax = COMN.CMAX;
qmax = COMN.QMAX;
lmax = COMN.ENDLIN;


/*  if comcnt > original command count, we update the sizes
    of the command/qualifier structures                */

mm =  KIWORDS[OFF_MONPAR];
nn =  KIWORDS[OFF_MONPAR+1];
if ( (mm > cmax) || (nn > qmax) )
   {
   COMN.CMAX = mm;
   COMN.QMAX = nn;
   COMN.ENDLIN = 10 * COMN.QMAX;    /* must be synchronized with newcom.exe */
   }


/*  now we can allocate the rest */
/*  comsize, qualsize + linesize must be computed just like in newcom.c !!   */

comsize = (sizeof(struct COMND_STRUCT)) * (COMN.CMAX+1);    /* for security */
tmpntr = malloc((size_t)comsize);
if (tmpntr == NULL)
   {
   printf("could not allocate %d bytes for COMND_STRUCT\n",comsize);
   ospexit(0);
   }
COMN.CP = (struct COMND_STRUCT *) tmpntr;

qualsize = (sizeof(struct QUALIF_STRUCT)) * (COMN.QMAX+1);   
tmpntr = malloc((size_t)qualsize);
if (tmpntr == NULL)
   {
   (void) printf("could not allocate %d bytes for QUALIF_STRUCT\n",qualsize);
   ospexit(1);
   }
COMN.QP = (struct QUALIF_STRUCT *) tmpntr;

linesize = (unsigned int) (COMN.ENDLIN + 4);
COMN.LINE = malloc((size_t)linesize);
if (COMN.LINE == NULL)
   {
   (void) printf("could not allocate %d bytes for COMLINE\n",
                  (int)linesize);
   ospexit(1);
   }


/*  O.K. now we read the stuff (in original size)  */

comsize = (sizeof(struct COMND_STRUCT)) * (cmax+1);
cpntr = (char *) COMN.CP;
stat = osdread(fp,cpntr,(unsigned int)comsize);
if (stat != comsize) goto osd_error;
	
qualsize = (sizeof(struct QUALIF_STRUCT)) * (qmax+1);
cpntr = (char *) COMN.QP;
stat = osdread(fp,cpntr,(unsigned int)qualsize);
if (stat != qualsize) goto osd_error;
	
linesize = (unsigned int) (lmax + 4);
stat = osdread(fp,COMN.LINE,linesize);
if (stat != (int)linesize) goto osd_error;

	
/*  close file again + set offset as needed for context level = 0  */
 
osdclose(fp);

#ifndef NO_READLINE
if (MONIT.CMD_LIST_UPDA == 1)
   update_cmd_list();
#endif

return(0);

osd_error:
(void) printf("Problems in reading from binary command file - %s\n",osmsg());
ospexit(1);

return 0;				/* just for the compiler... */
}
/*

*/
 
void EXTRACOM(input,comnd,qualif)

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  split input string of form command/qualifier into command + qualifier
.ALGORITHM
  split up command + qualifier and convert to upper case
.RETURNS  nothing
------------------------------------------------------------------*/
 
char	*input	/* IN: input string  */;
char	*comnd	/* OUT: isolated command (6 char)  */;
char	*qualif	/* OUT: isolated qualifier (4 char)  */;
 
{
int  qoff;
register int nr, mr;
static int   cdif = 'A' - 'a';

register char cc;




cc = input[0];
if (unlikely((cc == '/') || (cc == '\0')))
   {
   comnd[0] = '\0';                     /* bad command ...  */
   return;
   }

if ((cc >= 'a') && (cc <= 'z')) cc += cdif;
comnd[0] = cc;

qualif[0] = qualif[1] = qualif[2] = qualif[3] = ' ';


for (nr=1; nr<6; nr++)                  /*  pull out command */
   {
   cc = input[nr];
   if (cc == '\0')
      {                                 /* command without qualifier */
      for (mr=nr; mr<6; mr++) comnd[mr] = ' ';
      return;
      }
   if (cc == '/')
      {                                 /* we have a qualifier */
      for (mr=nr; mr<6; mr++) comnd[mr] = ' ';
      qoff = nr + 1;
      goto qualif_stuff;
      }

   if ((cc >= 'a') && (cc <= 'z')) cc += cdif;  /* move to upper case */
   comnd[nr] = cc;
   }

for (nr=6; ;nr++)                       /* skip over rest of command */
   {
   cc = input[nr];
   if (cc == '/')
      {
      qoff = nr + 1;
      goto qualif_stuff;
      }

   if (cc == '\0') return;		/* if no '/' found, we return here */
   }

qualif_stuff:
mr = 0;

for (nr=qoff; nr<qoff+4; nr++)          /*  pull out qualifier */
   {
   cc = input[nr];
   if (cc == '\0') return;

   if ((cc >= 'a') && (cc <= 'z')) cc += cdif;  /* move to upper case */
   qualif[mr++] = cc;
   }

}
/*

*/
 
int FINDCOM(comnd,qualif,defqual,defset,ctxno,line,linelen)
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  search for a given command / qualifier
.ALGORITHM
  compare only the no. of characters actually input - check also for ambiguities
  if found, store full command + qualifier into input pars
  also return pointer to connected command_line
.RETURNS int stat :	return status,
				= 0 if exact command/qualifier found
				= 1 if wild card command/qualifier found
				= 2, if command not found
				= 3, if qualifier not found
				= 8, if command ambiguous
				= 9, if qualifier ambiguous
-----------------------------------------------------------------------*/
char	*comnd    /* IO: input/full command  */;
char	*qualif   /* IO: input/full qualifier  */;
char	*defqual  /* OUT: default qualifier of command found  */;
int	 *defset  /* OUT: Defaults_defined_flag, 0 or 1  */;
int 	*ctxno   /* OUT: context no if >= 0,            \
			  if < 0 it's the index for primitive commands */;
char	**line	  /* OUT: pointer to command_line  */;
int 	*linelen /* OUT: length of command_line in bytes  */;
 
	
{
int   nroff, wild_indx, clen, qlen, retval;
int   foundc, foundq;

register int nr, mr;

register char *cptr;
	
	
 


/* get `length' of command + qualifier */

for (nr=5; nr>0; nr--)
   {
   if (comnd[nr] != ' ')
      {
      clen = nr + 1;
      goto quali;
      }
   }
clen = 1;

quali:
qlen = 4;
for (qlen=0; qlen<4; qlen++)
   {
   if (qualif[qlen] == ' ') break;
   }

 
/*    search commands first    */
 
foundc = -1;
nroff = 0;
retval = -1;			/* flag is set, when qualifier found */
compntr = COMN.CP;
 
				/* we can come back to here! */
cloop:
for (nr=nroff; nr <= COMN.INUSEC; nr++)
   {
   cptr = compntr->STR;
   for (mr=0; mr<clen; mr++)
      {
      if (comnd[mr] != *cptr++) goto next_c;
      }
   foundc = nr;
   nroff = nr + 1;
   goto after_cloop;

  next_c:
   compntr ++;				/* follow with pointer */
   }
 
if (foundc == -1) return (2);			/* command not found */
 
if (retval == 0)
   goto qual_found;			/* use last comm/qualif found */
else if (retval == 1)
   goto com_found;			/* don't modify `qualif'  */
else
   return (3);				/* command yes, qualif no */


		/*     search qualifiers next      */
 
after_cloop:
if (qlen == 0)	   /* if qualif = '   ', look first for blank qualif */
   {
   qlen = 4;
   nr = compntr->INDX;
   while (nr != -1)
      {
      qualpntr = COMN.QP + nr;
      if (qualpntr->STR[0] == ' ')
         {
         foundq = nr;
         goto after_qloop;
         }
      nr = qualpntr->NEXT;		/* follow to next qualifier */
      }
 
   cptr = compntr->QDEF;
   for (nr=0; nr<4; nr++) qualif[nr] = *cptr++; /* use default qualifier */
   }
	
	
	/*     main loop over qualifiers    */
 
foundq = -1;					/* reset found indicator  */
wild_indx = -1;

nr = compntr->INDX;
while (nr != -1)
   {
   qualpntr = COMN.QP + nr;
   if ( (qualpntr->STR[0] == '.') &&
        (qualpntr->STR[1] == '.') &&
        (qualpntr->STR[2] == '.') )     /* test, if "wild card" qualifier  */
      wild_indx = nr;

   else
      {
      cptr = qualpntr->STR;
      for (mr=0; mr<qlen; mr++,cptr++)
         {
         if (qualif[mr] != *cptr) goto next_q;
         }
     if (likely(foundq == -1))
         foundq = nr;
      else                              /* ambiguous qualifier */
         return (9);
      }
next_q:
   nr = qualpntr->NEXT;			/* follow to next qualifier */
   }
 

after_qloop:
if (foundq != -1)
   {
   if (retval != -1) return (8);	/* we had a match before */
 
   retval = 0;
   qnext = COMN.QP + foundq;
   }
else					/* no match with any qualifier */
   {
   if (wild_indx == -1) 		/* also no wild_card match */
      {
      if (clen < 6)
         {
         compntr ++;                         /* follow with pointer */
         goto cloop;			/* check the other commands */
         }
      else
         return (3);
      }
 
   if (retval != -1) return (8);	/* we had a match before */
 
   retval = 1;
   qnext = COMN.QP + wild_indx;		/* wild card qualifier...   */
   if (clen >= 6) 			/* if "full" command, we're done */
      {
      cnext = compntr;		/* use input qualif + save comnd pointer */
      goto com_found;
      }
   }

cnext = compntr;		/* qualifier o.k., so save comnd pointer */
if (clen < 6) 
   {
   compntr ++;                         /* follow with pointer */
   goto cloop;			/* check the other commands */
   }
 
 
/*  return command/qualifier type and actual command line   */

qual_found:
cptr = qnext->STR;
for (nr=0; nr<4; nr++) qualif[nr] = *cptr++; /* store full qualif. string */

com_found:
cptr = cnext->STR;
for (nr=0; nr<6; nr++) comnd[nr] = *cptr++;	/* store full command string */
cptr = cnext->QDEF;
for (nr=0; nr<4; nr++) defqual[nr] = *cptr++;	/* store default qualifier */
*defset = qnext->DEFSET;
nr = qnext->CTXNO;

if (nr == -2)
   *ctxno = qnext->OFF;			/* primitive command  */
else
   {	
   *line = COMN.LINE+qnext->OFF;
   *linelen = (int)strlen(*line);
   if (nr == -1)
      *ctxno = 99;				/* fixed added commands */
   else
      *ctxno = qnext->CTXNO;		/* 0, 1, ..., MAX_CONTXT  */
   }
 
return (retval);
}
/*

*/
 
int ADDCOM(comnd,qualif,type,lenoff,line)
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  add a command / qualifier (and default qualifier)
.ALGORITHM
  add new command or increment qualifier pointers, if command already exists,
  add new qualifier and default qualifier and actual command line
  (only, if same command line does not exist yet)
.RETURNS int stat :	return status
                                = 0, if command/qualifier successfully added
				= 10, if command / qualifier already exists or
                                      would lead to ambiguity
				= 10, if new command / qualifier would be
                                      ambiguous
				= 42, if overflow in command table
				= 42, if overflow in qualifier table
				= 42, if overflow in actual command table
				= 5, if no command line at all
				= 42, if comnd def. line + lenoff > COMN.ENDLIN
-----------------------------------------------------------------------*/
char	*comnd   /* IN: command string  */;
char	*qualif  /* IN: qualifier string  */;
int  	type  /* IN: type of new command:            \
                        = -2 for primitive commands     \
                        = -1 for fixed added commands   \
                        >= 0 for dynamic commands       */;
int 	lenoff /* IN: no. of spaces to add to end of command string  */;
char	*line    /* IN: actual command line, terminated by \0  */;
 
{
int   mm, k, next, linelen, nsav;
int   foundc, foundq;
	
char	*cpntra, *cpntr;

register int nr;
 
 

if ((COMN.INUSEQ == COMN.QMAX) ||	/* at the top end, try to pack first */
    (COMN.INUSEC == COMN.CMAX))
   {
   k = PACKCOM();
   if (k != 0) return (42);
   }
	
 
cpntr = (char *) 0;
next = nsav = 0;
 
if (type > -2)				/* get length of command definition */
   {
   linelen = (int)strlen(line);
   for (nr=linelen-1; nr>0; nr--)
      if (line[nr] != ' ') break;	/* get rid of trailing blanks  */

   linelen = nr + 1;
   mm = lenoff + linelen + 1;	   /* get length of comnd_str (incl. '\0') */
 
   if ( (COMN.FIRST + mm) > COMN.ENDLIN)
      {
      k = PACKCOM();
      if (k != 0) return (42);
      }

   cpntr = COMN.LINE + COMN.FIRST;	/* there is enough space, so we use  */
   (void)
   memcpy(cpntr,line,(size_t)linelen);	/* COMN.LINE now as working buffer   */
   cpntra = cpntr + linelen;
   if (lenoff == 1) *cpntra++ = ' ';
   *cpntra = '\0';			/* terminate it */

   next = mm + COMN.FIRST;		/* point already to next free index  */
   COMN.STRL = mm;			/* save that length */
   }
	
	
/*  check, if command already exists (is permitted)  */
 
compntr = COMN.CP;			/* initialize pointers */
qualpntr = COMN.QP;

for (foundc=0; foundc <= COMN.INUSEC; foundc++)
   {
   k = MINMATCH(comnd,compntr->STR,6);
   if (k == 2)
      return (10);			/* new command would be ambiguous... */
   else if (k == 1)
      goto cmnd_exist;			/* new command exists already */
   compntr ++;
   }

	
/*  add new command + qualifier        */
 
if ((COMN.INUSEQ == COMN.QMAX) || (COMN.INUSEC == COMN.CMAX))
   return (42);

foundc = ++ COMN.INUSEC;		/* increment COMN.INUSEC first */
foundq = ++ COMN.INUSEQ;
compntr = COMN.CP + foundc;
qualpntr = COMN.QP + foundq;
 
cpntr = compntr->STR;
for (nr=0; nr<6; nr++) *cpntr++ = comnd[nr];

cpntr = compntr->QDEF;
cpntra = qualpntr->STR;
for (nr=0; nr<4; nr++)
   {
   *cpntr++ = qualif[nr];
   *cpntra++ = qualif[nr];
   }

compntr->INDX = (short int) foundq;
qualpntr->LAST = (short int) (-(foundc + 1));	/* will be the 1. qualifer */
qualpntr->NEXT = -1;			/* indicate that here is the end  */
goto sect_2500;				/* continue like the others...   */
	

/*  command already exists - now check qualifier  */
 
cmnd_exist:
 
foundq = compntr->INDX;
while (foundq != -1)
   {
   qualpntr = COMN.QP + foundq;
   k = MINMATCH(qualif,qualpntr->STR,4);
   if (k == 2)
      return (10);			 /* new command would be ambiguous  */
   else if (k == 1)
      {
      if (KIWORDS[OFF_ERROR+1] < 2) 		/* for non-experts  */
         return (10);				/* that's an error...  */

      nr = qualpntr->OFF;
      k = COMUSED(nr);      /* see, if other comnd is accessing this string */
      if (k == -1)
         {
         *(COMN.LINE+nr) = '\\';                /* undo corresp. comnd line */
         if (nr < COMN.FDEL) COMN.FDEL = nr;    /* update first_deleted_indx */
         }
      (void)printf("existing command overwritten...\n");
      goto sect_2500;                           /* just modify command line  */
      }
   foundq = qualpntr->NEXT;			/* chain to next entry */
   }
 
 
if (COMN.INUSEQ == COMN.QMAX) return (42);

foundq = ++ COMN.INUSEQ;
qualpntr = COMN.QP + foundq;
cpntra = qualpntr->STR;                         /* cpntr is still in use! */
for (nr=0; nr<4; nr++) *cpntra++ = qualif[nr];
 
	
/*  now link qualifier in  */
 
nr = compntr->INDX;
while (nr != -1)
   {
   nsav = nr;
   qualpntr = COMN.QP + nr;
   nr = qualpntr->NEXT;
   }

qualpntr = COMN.QP + nsav;
qualpntr->NEXT = (short int) foundq;		/* link forward + backward  */
qualpntr = COMN.QP + foundq;
qualpntr->LAST = (short int) nsav;
qualpntr->NEXT = -1;			/* indicate that here is the end  */
 
 
 
/* add command line and update QP.OFF  */
	
sect_2500:
 
qualpntr->CTXNO = (short int) type;			/* save context no. */
if (type == -2) 					/* primitive command */
   {
   nsav = -( COMN.INUSEQ + 1);		/* put into [-1,-...]  */
   goto final_step;
   }
 
/*   check, if command line already in command buffer   */
 
for (nr=0; nr<COMN.FIRST; nr+=(int)strlen(COMN.LINE+nr)+1)
   {
   if (strcmp(COMN.LINE+nr,cpntr) == 0)
      {
      nsav = nr;
      goto final_step;
      }
   }
 
 
/*   command line not there yet,  we have to add   */
 
nsav = COMN.FIRST;		/* remember, that string is already there  */
COMN.FIRST = next;				/* update COMN.FIRST  */
 
 
final_step:
qualpntr->OFF = (short int) nsav;	
qualpntr->DEFSET = 0;			/* initially set to 0  */

#ifndef NO_READLINE
MONIT.CMD_LIST_UPDA = 1;		/* mark for action ... */
#endif

return (0);
}
/*

*/

int DELCOM(comnd,qualif)
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  delete a command / qualifier (and default qualifier)
.ALGORITHM
  delete a command, default qualifier + qualifier or
  only decrement qualifier pointers, if command has more qualifiers
  and compress qualifier + com line table
.RETURNS
  return status, = 0 if command/qualifier successfully deleted
 		= -1, if command does not exist
		= -2, if qualifier does not exist
		= +1, if command/qualifier is not a dynamic command 
		      (can not be removed)
--------------------------------------------------------------*/
char	*comnd	/* IN: command string (not terminated by \0) */;
char	*qualif /* IN: qualifier string (not terminated by \0) */;
	
{
int   foundc, foundq;


/*    find command       */ 

compntr = COMN.CP;
for (foundc=0; foundc<=COMN.INUSEC; foundc++)
   {
   if (strncmp(comnd,compntr->STR,6) == 0) goto qualif_sect;
   compntr ++;
   }
return (-1);			/*   command does not exist   */
	
 
/*    find qualifier     */
 
qualif_sect:
foundq = compntr->INDX;
 
while (foundq != -1)
   {
   qualpntr = COMN.QP + foundq;
   if (strncmp(qualif,qualpntr->STR,4) == 0) goto remove_sect;
   foundq = qualpntr->NEXT;
   }
return (-2);			/*  qualifier not found   */
 
 
/*  command/qualifier found:
    remove (command and) qualifier + actual command line          */
 
remove_sect:
if (qualpntr->CTXNO == -2)
   return (1);			    /* not a dynamically added command...  */
 
	
/*  everything o.k.  (more or less...)   */
 
cut_links();		/* remove qualifier (and command)  */


/* if last qualifier and/or command decrement qual/com limits */

if (foundq == COMN.INUSEQ) COMN.INUSEQ -- ;
if ((compntr->STR[0] == '\\') && (foundc == COMN.INUSEC))
   COMN.INUSEC -- ;

return (0);
}
/*

*/
 
int SETDFF(comnd,qualif,flag)
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  toggle the Defaults_defined_flag for a command / qualifier
.ALGORITHM
  find the entry + change COMN.Q[].DEFSET
.RETURNS
  return status, = 0 if command/qualifier successfully updated
 		= -1, if command does not exist
		= -2, if qualifier does not exist
--------------------------------------------------------------*/
char	*comnd	 /*IN: command string (not terminated by \0)   */;
char	*qualif  /*IN: qualifier string (not terminated by \0) */;
int  flag   /*IN: 0 or 1                                  */;
	
{
int   foundc, foundq;


/*    check, if command exists   */
 
compntr = COMN.CP;
for (foundc=0; foundc<=COMN.INUSEC; foundc++)
   {
   if (strncmp(comnd,compntr->STR,6) == 0) goto qualif_sect;
   compntr ++;
   }
	
return (-1);				/*   command does not exist   */
	
 
/*    find qualifier     */
 
qualif_sect:
foundq = compntr->INDX;
 
while (foundq != -1)
   {
   qualpntr = COMN.QP + foundq;
   if (strncmp(qualif,qualpntr->STR,4) == 0) 
      {
      qualpntr->DEFSET = (short int) flag;    /* toggle Defaults_defd_flag */
      return (0);
      }

   foundq = qualpntr->NEXT;
   }
 
return (-2);				/*  qualifier not found   */
}
/*

*/

int COMUSED(koff)

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  search through all qualifiers to see if command string at
  COMN.LINE+nr is referenced
.ALGORITHM
  loop through qualifs and check qualif->OFF
.RETURNS
  index of qualifer, if string is referenced, -1 if not
-----------------------------------------------------------------*/
int koff;

{
int  mm;
register int  nr;


qnext = COMN.QP;
for (nr=0; nr<COMN.INUSEQ; nr++)
   {
   if ((qnext->OFF == koff) && (qnext->STR[0] != '\\'))
      {
      mm = nr;
      return(mm);				/* com/qualif found */
      }
   qnext ++;
   }
						/* nothing found */
return (-1);
}
/*

*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  remove a command/qualif combination from the data structure
.ALGORITHM
  work on qualifs, command line + maybe command itself
.RETURNS
  nothing
-----------------------------------------------------------------*/

void cut_links()

{
int   k, last, next, mm;


qualpntr->STR[0] = '\\';                /* this pulls it out of the action  */

next = qualpntr->NEXT;                          /* get qualifier after     */
qnext = COMN.QP + next;
last = qualpntr->LAST;                          /* get qualifier in front  */
qlast = COMN.QP + last;

if (last >= 0)
   {                                    /* still a qualifier before us  */
   qlast->NEXT = (short int) next;
   if (next >= 0) qnext->LAST = (short int) last;
   }
else
   {			/* we are the first qualifier of this command */
   if (next == -1)
      compntr->STR[0] = '\\';
   else
      qnext->LAST = (short int) last;
   }

mm = qualpntr->OFF;		/* OFF is > 0 !! */
k = COMUSED(mm);
if (k == -1)
   {
   if (mm < COMN.FDEL) COMN.FDEL = mm;	   /* update first_deleted_index */
   k = COMN.FIRST - COMN.STRL;
   if ((COMN.FIRST-COMN.STRL) == mm)	/* was that the last string? */
      {
      int  nr, ns;

      COMN.FIRST = k; 
      nr = k;
      while(*(COMN.LINE+nr) != '\0')       /* get 1. char. of command line  */
         nr -- ;
      ns = nr + 1;
      COMN.STRL = (int) strlen(COMN.LINE+ns) + 1;
      }
   else
      *(COMN.LINE+mm) = '\\';
   }


#ifndef NO_READLINE
MONIT.CMD_LIST_UPDA = 1;		/* mark for action ... */
#endif
}
/*

*/
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  delete all commands/qualifiers of a given context no.
  that is, delete all c/q's with    COMN.Q[n].CTXNO = ctxno
.ALGORITHM
  loop through COMN.Q.OFF to find a matching ctxno 
  when found, work backwards to get corresponding command/qualifier combination
  and use function cut_links to remove that pair
.RETURNS  nothing
------------------------------------------------------------------*/
 
void CLEANCOM(ctxno)
int   ctxno	 /* IN: > 0, delete all com/qual with matching CTXNO \
				= 0, delete all com/qual with CTXNO > 0 */;
 
{
register int nr, rq;
 
 
qualpntr = COMN.QP + COMN.LPRIMQ + 1;
for (nr=COMN.LPRIMQ+1; nr<=COMN.INUSEQ; nr++)
   {					/* loop through array Q.OFF  */
   if (qualpntr->CTXNO > 0)		/* from a context ? */
      {
      if ((ctxno == 0) || (qualpntr->CTXNO == ctxno))
         {
         rq = qualpntr->LAST;			/*  unravel backwards  */
         while (rq >= 0)
            {
            qlast = COMN.QP + rq;
            rq = qlast->LAST;
            } 
         compntr = COMN.CP - (rq + 1); 
         cut_links();
         }
      }
   qualpntr ++;
   }
 
(void) PACKCOM();				/* sqeeze everything together again */
}
/*

*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  compress the command data base
.ALGORITHM
  remove any deleted commands, qualifiers
.RETURNS 
  completion status = 0, o.k.we could clean up
                    = 1, nothing we could do...
-----------------------------------------------------------------*/

int PACKCOM()
 
{
int   mm, k, np, nt, ns;

register int nr;



/*  look for deleted command entries  */

compntr = COMN.CP + COMN.LPRIMC;
for (nr=COMN.LPRIMC; nr <= COMN.INUSEC; nr++)
   {
   if (compntr->STR[0] == '\\') goto its_ok;
   compntr ++;
   }

qualpntr = COMN.QP + COMN.LPRIMQ;
for (nr=COMN.LPRIMQ; nr <= COMN.INUSEQ; nr++)
   {
   if (qualpntr->STR[0] == '\\') goto its_ok;
   qualpntr ++;
   }

return (1);             /* nothing to do */


/*  remove deleted command entries from the top  */

its_ok:
compntr = COMN.CP + COMN.INUSEC;
while (compntr->STR[0] == '\\')
   {
   COMN.INUSEC --;
   compntr --;
   }
 
/*  now move from COMN.LPRIMC upward + copy last entry into any free entry  */
 
mm = COMN.LPRIMC;
 
comnd_loop:
 
for (nr=mm+1; nr<=COMN.INUSEC; nr++)
   {
   compntr = COMN.CP + nr;
   if (compntr->STR[0] == '\\')		/* look for free entry  */
      {
      nt = COMN.INUSEC;
      cnext = COMN.CP + nt;
      if (cnext->STR[0] != '\\')		/* only copy "full" entries */
         {
         (void)memcpy(compntr->STR,cnext->STR,(size_t)6);
         (void)memcpy(compntr->QDEF,cnext->QDEF,(size_t)4);
         np = cnext->INDX;		/* we also have to modify the link */
         qualpntr = COMN.QP + np;
         qualpntr->LAST = (short int) (-(nr+1)); 	/* to the qualifier  */
         compntr->INDX = (short int) np;
         }
      else
         nr -- ;
 
      mm = nr;				/* this will be the new start  */
      COMN.INUSEC -- ;
      goto comnd_loop;
      }
   }
 
 
/*  remove deleted qualifier entries from the top  */
 
qualpntr = COMN.QP + COMN.INUSEQ;
while (qualpntr->STR[0] == '\\')
   {
   COMN.INUSEQ --;
   qualpntr --;
   }

 
/*  now move from COMN.LPRIMQ upward + copy last entry into any free entry  */
 
mm = COMN.LPRIMQ;
 
qualif_loop:
 
for (nr=mm+1; nr<=COMN.INUSEQ; nr++)
   {
   qualpntr = COMN.QP + nr;
   if (qualpntr->STR[0] == '\\')		/* look for free entry  */
      {
      nt = COMN.INUSEQ;
      qnext = COMN.QP + nt;
      if (qnext->STR[0] != '\\')	/* only copy "full" entries... */
         {
         (void)memcpy(qualpntr->STR,qnext->STR,(size_t)4);
         np = qnext->LAST;		/* we also have to modify the links
					   to the other commands  */
         qualpntr->LAST = (short int) np;
         qualpntr->NEXT = qnext->NEXT;
         qualpntr->DEFSET = qnext->DEFSET;
         qualpntr->CTXNO = qnext->CTXNO;
         qualpntr->OFF = qnext->OFF;
         if (np >= 0)			/* either link with other qualifs  */
            {
            qlast = COMN.QP + np;
            qlast->NEXT = (short int) nr;
            }
         else				/* or link back to commands  */
            {
            ns = -1 - np;		/* index in commands structure */
            cnext = COMN.CP + ns;
            cnext->INDX = (short int) nr;
            }

         np = qnext->NEXT;              /* look for next qualifier */
         if (np >= 0)                   /* and update link */
            {
            qlast = COMN.QP + np;
            qlast->LAST = nr;
            }
         }
      else
         nr -- ;
 
      mm = nr;				/* this will be the new start  */
      COMN.INUSEQ -- ;
      goto qualif_loop;
      }
   }
 
 
/*  first, try to remove deleted command lines from the top  */
 
k = COMN.FIRST - 2;			/* point to last char. before NULL  */
 
line_loop_1:
nr = k;
while(*(COMN.LINE+nr) != '\0')       /* get first char. of this command line  */
   nr -- ;
ns = nr + 1;

if (*(COMN.LINE+ns) == '\\')
   {
   k = ns - 2;		     /* point to last char of previous command line  */
   goto line_loop_1;
   }
 
 
/*  now move from COMN.FDEL upward 
    and shift remainder into any free command line         */
 
COMN.FIRST = k + 2;
mm = COMN.FDEL;
 
line_loop_2:
for (nr=mm; nr<COMN.FIRST; nr+=((int)strlen(COMN.LINE+nr)+1))
   {
   if (*(COMN.LINE+nr) == '\\')		/* look for deleted command line  */
      {
      nt = nr + (int)strlen(COMN.LINE+nr) + 1;	/* point to next string */
      for (k=nt; k<COMN.FIRST; k+=(int)strlen(COMN.LINE+k)+1)
         {
         if (*(COMN.LINE+k) != '\\')		/* more deleted strings? */
            {
            nt = k;
            break;
            }
         }
 
      np = k - nr;
      for (k=nt; k<COMN.FIRST; k+=(int)strlen(COMN.LINE+k)+1)
         MODOFF(k,np);			/*  update the offset in Q.OFF  */

      CGN_COPYALL(COMN.LINE+nr,COMN.LINE+nt,COMN.FIRST-nt);
      COMN.FIRST -= np ;
      mm = nt;
      goto line_loop_2;
      }
   }

COMN.FDEL = COMN.FIRST;
return (0);
}
/*

*/

void MODOFF(off,m)
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  utility to modify the offsets for qualifiers
.ALGORITHM
  painful
.RETURNS 
  nothing
-----------------------------------------------------------------*/
int   off	/* IN: current qualifier offset  */;
int   m    /* IN: amount for decrementing  */;
 
{
int mm; 
 
register int nr;
 
 
/*  search through qualifiers to find given offset   */
 
mm = COMN.LPRIMQ + 1;		/* start after primitive qualifiers */
qualpntr = COMN.QP + mm;

for (nr=mm; nr<=COMN.INUSEQ; nr++)
   {				/* decrement the offset by given amount */
   if (qualpntr->OFF == off) qualpntr->OFF -= m;
   qualpntr ++;
   }
}
/*

*/
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  update default qualifier for all commands with given qualif or wild card (...)
  (comnd = *) or specific commnds (comnd = command name)
.ALGORITHM
  if found, store default qualifier into COMN.C.QDEF
.RETURNS
  nothing
-----------------------------------------------------------------------*/
 
void DEFCOM(comnd,qualif)
char	*comnd  /* IN: command string (not terminated by \0) or '*' */;
char	*qualif /* IN: qualifier string (not terminated by \0) */;
 
{
int   found, kstrn;
register int nr;
 
 
if (qualif[0] == ' ') return;		/* blank qualifier not allowed  */
 
kstrn = 4;
for (nr=0; nr<4; nr++)
   {
   if ((qualif[nr] == ' ') || (qualif[nr] == '\0'))
      {
      kstrn = nr;
      break;
      }
   }

compntr = COMN.CP;
if (*comnd == '*')
   {
   for (nr=0; nr<=COMN.INUSEC; nr++)
      {
      found = compntr->INDX; 
      while (found != -1)         /*  loop through all connected qualifiers  */
         {
         qualpntr = COMN.QP + found;
         if ( (strncmp(qualif,qualpntr->STR,kstrn) == 0) ||
              ( (qualpntr->STR[0] == '.') &&
                (qualpntr->STR[1] == '.') &&
                (qualpntr->STR[2] == '.') ) )
            {
            (void)memcpy(compntr->QDEF,qualif,(size_t)4);
            break;
            }
         else
            found = qualpntr->NEXT;
         }

      compntr ++;
      }
   }
else
   {
   for (nr=0; nr<=COMN.INUSEC; nr++)
      {
      found = MINMATCH(comnd,compntr->STR,6);
      if (found != 0)
         (void)memcpy(compntr->QDEF,qualif,(size_t)4);

      compntr ++;
      }
   }
}
/*

*/
 
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  show the data structures holding the commands + qualifiers
.ALGORITHM
  straight forward - once you know the data structures...
.RETURNS  = 0, o.k.
          = -1, if `com/qualif' not found, i.e. only applicable to that case!

------------------------------------------------------------------*/

int SHOWCOM(fp,option,qualif)
int     fp      /* IN: file identifier obtained from osaopen  
                       if = -1, output to terminal instead   */;
char    *option /* IN: display option:                        
                       = D for diagnostic (complete) display 
                       = ' ' for display of only the dynamically added commands
                       = Q show all commands with given qualifer  
                       = A show all commands beginning with given string 
                       = 'com/qualif' for display of single command  */;

char    *qualif /*IN: qualifier for option Q above  */;

{
char    com1[8], qual1[8], defqual[8], buf[20], *cpntr;
char    record[84];

int   found, foundc, ffp, kstrn, mm, qlen, i, ii, nn;
register int  nr;



        /*  diagnostic display of all tables   */

if (option[0] == '-')
   {
   if ((option[1] == 'X') || (option[1] == 'x')) goto comn_only;

   (void)strcpy(record,"---------------------------");
   spitout(fp,record);
   (void) sprintf(record,"C:   STR     QDEF    INDX");
   spitout(fp,record);
   (void)strcpy(record,"---------------------------");
   spitout(fp,record);

   for (nr=0; nr <= COMN.INUSEC; nr++)
      {
      compntr = COMN.CP + nr;
      (void) sprintf(record,"%3.3d: %6.6s  %4.4s   %4d",
              nr,compntr->STR,compntr->QDEF,compntr->INDX);
      spitout(fp,record);
      }

   (void)strcpy(record,"---------------------------------------------");
   spitout(fp,record);
   (void) sprintf(record,"Q:   STR     LAST   NEXT    OFF  DEFSET CTXNO");
   spitout(fp,record);
   (void)strcpy(record,"---------------------------------------------");
   spitout(fp,record);

   for (nr=0; nr <= COMN.INUSEQ; nr++)
      {
      qualpntr = COMN.QP + nr;
      (void) sprintf(record,"%3.3d: %4.4s   %4d   %4d   %4d     %d     %d",
              nr,qualpntr->STR,qualpntr->LAST,qualpntr->NEXT,qualpntr->OFF,
              qualpntr->DEFSET,qualpntr->CTXNO);
      spitout(fp,record);
      }

   (void)strcpy(record,"-----------------");
   spitout(fp,record);
   (void) sprintf(record,"buffer COMN.LINE:");
   spitout(fp,record);
   (void)strcpy(record,"-----------------");
   spitout(fp,record);

   nr = 0;
   while(nr < COMN.FIRST)
      {
      (void) sprintf(record,"%4.4d: %s",nr,COMN.LINE+nr);
      spitout(fp,record);
      nr += (int)strlen(COMN.LINE+nr) + 1;
      }

comn_only:
   (void) sprintf(record,"INUSEC: %d   INUSEQ: %d ",COMN.INUSEC,COMN.INUSEQ);
   spitout(fp,record);
   (void) sprintf(record,"CMAX: %d     QMAX: %d  ENDLIN: %d",
              COMN.CMAX,COMN.QMAX,COMN.ENDLIN);
   spitout(fp,record);
   (void) sprintf(record,"FIRST: %d ",COMN.FIRST);
   spitout(fp,record);
   (void) sprintf(record,"LPRIMC: %d   LPRIMQ: %d   FDEL: %d",
              COMN.LPRIMC,COMN.LPRIMQ,COMN.FDEL);
   spitout(fp,record);

   return 0;
   }


/*  check, if single command option  */

if (option[1] != ' ')
   {
   int  retstat = 0;

   EXTRACOM(option,com1,qual1); 
   i = FINDCOM(com1,qual1,defqual,&nn,&ii,&cpntr,&mm); 

   if (i > 1)
      {
      retstat = -1;
      (void)strcpy(record,"given command/qualif not defined ...");
      }
   else
      {
      if (i == 1)                               /* wild card match */
         {
         (void) strcpy(buf,"... ");
         (void) memcpy(qual1,buf,(size_t)4);
         }
      com1[6] = '\0';
      qual1[4] = '\0';
      defqual[4] = '\0';
      (void) sprintf(record,
                     "%6.6s/%4.4s   (def_qualif %4.4s )  defaults_flag: %d",
                     com1,qual1,defqual,nn);

      if (ii < 0)
         {
         record[34] = '\0';
         spitout(fp,record);
         (void)strcpy(record,"primitive command ");
         }
      else
         {
         spitout(fp,record);
         (void)strcpy(record,cpntr);
         }
      }

   spitout(fp,record);
   return retstat;
   }


        /*  display of dynamically added commands   */

if (option[0] == ' ')
   {
   qualpntr = COMN.QP + COMN.LPRIMQ + 1;
   for (nr=COMN.LPRIMQ+1; nr <= COMN.INUSEQ; nr++)
      {
      if ((qualpntr->CTXNO >= 0) && (qualpntr->STR[0] != '\\'))
         {
         nn = qualpntr->LAST;
         while (nn >= 0)
            {
            qnext = COMN.QP + nn;
            nn = qnext->LAST;
            }
         foundc = -1 - nn;
         mm = qualpntr->OFF;
         compntr = COMN.CP + foundc;
         (void) sprintf(record,"%6.6s/%4.4s (%d):  %s",
                 compntr->STR,qualpntr->STR,qualpntr->CTXNO,COMN.LINE+mm);
         spitout(fp,record);
         }
      qualpntr ++;
      }
   }


        /*  display of all commands with given qualifier   */

if ((option[0] == 'Q') || (option[0] == 'q'))
   {
   ffp = CGN_OPEN("MID_MONIT:wildcom.in",0);   /* file wildcom.in needed for
                                                 wildcard qualifiers       */
   found = 0;                           /* use as counter */
   qlen = (int)strlen(qualif);
   if (qlen <= 4)
      {
      kstrn = qlen;
      if ((kstrn == 1) && (qualif[0] == '?'))
         {
         qualif[0] = '.';               /* default to wildcard qualifier */
         qualif[1] = '.';
         qualif[2] = '.';
         qualif[3] = '\0';
         kstrn = 3;
         }
      }
   else
      kstrn = 4;

   for (nr=0; nr <= COMN.INUSEQ; nr++)
      {
      qualpntr = COMN.QP + nr;
      if (strncmp(qualpntr->STR,qualif,kstrn) == 0)
         {                      /* if we found something get to the command  */
         nn = qualpntr->LAST;
         while (nn >= 0)
            {
            qnext = COMN.QP + nn;
            nn = qnext->LAST;
            }

         foundc = -1 - nn;
         compntr = COMN.CP + foundc;
         (void) sprintf(record,"%6.6s/%4.4s",compntr->STR,qualpntr->STR);
         spitout(fp,record);
         found ++;
         }

      else if ((qualpntr->STR[0] == '.') && (qualpntr->STR[1] == '.'))
         {                              /* if we found a wildcard qualifier */
         nn = qualpntr->LAST;
         while (nn >= 0)
            {
            qnext = COMN.QP + nn;
            nn = qnext->LAST;
            }

         foundc = -1 - nn;
         compntr = COMN.CP + foundc;
         if (ffp != -1)                 /* see if it hides a match */
            {
read_wild:
            mm = osaread(ffp,buf,18);
            if (mm == -1) goto end_wild;

            if (strncmp(buf,compntr->STR,6) != 0)
               goto read_wild;

            i = 0;
            while (buf[i] != '/' ) i ++;                /* move to '/'  */
            if (strncmp(&buf[i+1],qualif,kstrn) != 0)
               goto read_wild;

            (void) sprintf(record,"%6.6s/%4.4s",compntr->STR,&buf[i+1]);
            spitout(fp,record);
            found ++;

end_wild:
            mm = (int) osaseek(ffp,0L,FILE_START);            /* rewind file */
            }
         }
      }

   if (found == 0)
      {
      (void) strncpy(buf,qualif,(size_t)kstrn);
      buf[kstrn] = '\0';
      (void) sprintf(record,"no command found for given qualifier: %s",buf);
      spitout(fp,record);
      (void)strcpy(record,
"but check also the commands with qualifier '...' (the `wildcard' qualifier)");
      spitout(fp,record);
      (void)strcpy(record,"via the command HELP/QUAL ...");
      spitout(fp,record);
      }

   if (ffp != -1) osaclose(ffp);
   }

        /*  display of all commands begining with given char.string */

else if ((option[0] == 'A') || (option[0] == 'a'))
   {
   qlen = (int)strlen(qualif);
   if (qlen <= 6)
      kstrn = qlen;
   else
      kstrn = 6;

   i = 0;
   for (nr=0; nr <= COMN.INUSEC; nr++)
      {
      compntr = COMN.CP + nr;
      if (strncmp(compntr->STR,qualif,kstrn) == 0)
         {
         i = 1;
         (void) sprintf(record,"%6.6s",compntr->STR);
         spitout(fp,record);
         }
      }

   if (i == 0)
      {
      (void)strcpy(record,"no command found ...");
      spitout(fp,record);
      }
   }
return 0;
}
/*

*/

void spitout(tp,rbuf)

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  write out record to file or terminal
.ALGORITHM
  clear
.RETURNS
  nothing
-----------------------------------------------------------------*/
int     tp      /* IN: file pointer  */;
char    *rbuf /* IN: data buffer  */;

{
int   mm, unit;

register int nr;


mm = (int)strlen(rbuf);
if (tp >= 0)
   osawrite(tp,rbuf,mm);
else
   {
   SCTPUT(rbuf);
   for (nr=mm; nr<80; nr++)
      rbuf[nr] = ' ';                 /* fill with blanks */
   rbuf[80] = '\0';
   SCKWRC("OUTPUTC",1,rbuf,1,80,&unit);      /* save also in key OUTPUTC */
   }
}
 
