
#if !defined(COMPILE_ENVIRONMENT)
#include <gp/stdcenvf.h> /* std compile environment for functions */
#endif

/***************************************************************/
/* file sm_pkg1pr.c                                            */
/* a package of functions to post-process an alignment to      */
/* handle splits and merges, using protected strings.          */
/* For typical uses of the functions, see the program tald3c   */
/* or the function aldistsm_prot.                              */
/*                                                             */
/* Highest-level functions are:                                */
/* sm_correction2_prot(alnx,smtab,) - fills smtab based on alnx*/
/* sort_sm_by_iloc(smtab) -  sorts smtab by index position     */
/* put_sm_into_aln_prot(alnx,smtab,...) - puts sm's into alnx  */
/* dump_smtab1(smtab) - dumps an smtab                         */
/*                                                             */
/* Other functions used:                                       */
/* sm_correction2_prot(alnx,smtab,...)                         */
/*   find_sm2_prot();                                          */
/*     rate_sm_prot();                                         */
/*     save_sm();                                              */
/*   sort_sm_by_fom();                                         */
/*     interchange_entries();                                  */
/*   sm_overlap();                                             */
/*     limits()                                                */
/*   save_sm();                                                */
/*   dump_smtab();                                             */
/* sort_sm_by_iloc(smtab)                                      */
/*   interchange_entries();                                    */
/* put_sm_into_aln_prot(alnx,smtab,...)                        */
/*   add_to_auxtab_prot();                                     */
/*                                                             */
/***************************************************************/


static void rate_sm_prot(SM_ELEMENT2 *smrep, ALIGNMENT_INT_PROT *pal1)
/********************************************/
/*  Calculates quantitative values for      */
/* rating the sm *smrep.                    */
/********************************************/
 {char *proc = "rate_sm_prot";
  pcodeset *pcode1;
  ALIGNMENT_INT_PROT *pal2;
  ALIGNMENT_INT_PROT *pdummy = (ALIGNMENT_INT_PROT *)NULL;
  ALIGNMENT_INT_PROT *palx;
  int i,j,k,err, *perr = &err;
  PROTECTED_CHR_STR sxdbx, *sxdb = &sxdbx;
  PROTECTED_INT_STR sxix, *sxi = &sxix;
  boolean return_alignment = T, dont_return_alignment = F;
/* code: */
db_enter_msg(proc,0); /* debug only */
/* initialize */
  alloc_prot_int_str_guts(sxi,26);
  alloc_prot_chr_str_guts(sxdb,133);
  pcode1 = pal1->pcset;
  pal2 = make_al_int_prot2("rate_sm_prot/pal2",pcode1->lower_code);
  pal2->aligned = F;
if (db_level > 1) dump_pcode2(pal2->pcset);
if (db_level > 1) dump_ppf2(pal2->pcset);
if (db_level > 1) dump_auxtab_prot(pal1);
  i = smrep->ival; j = smrep->jval; k = smrep->kval;
  palx = make_al_int_prot2("rate_sm_prot/palx",pcode1->lower_code);
  palx->aligned = F;
if (db_level > 0)
 {printf("%s ival=%d, jval=%d, kval=%d\n",pdb,i,j,k);
  printf("%s s_or_m=%c, l_or_r=%c\n",pdb,smrep->s_or_m,smrep->l_or_r);
 }
if (db_level > 0)
 {printf("%s ival phones='%s'\n",pdb,ascii_stri_prot(sxdb,i,pcode1,pal1));
  printf("%s jval phones='%s'\n",pdb,ascii_stri_prot(sxdb,j,pcode1,pal1));
  printf("%s kval phones='%s'\n",pdb,ascii_stri_prot(sxdb,k,pcode1,pal1));
 }
/* compute pdist hypothesizing split or merge */
if (db_level > 0) printf("%s computing Dph under s/m hypothesis.\n",pdb);
  if (smrep->s_or_m == 's')
    {nstrcpy_prot_s(pal2->nsa,lc_istr_prot(sxi,i,pcode1,pal1));
     nstrcpy_prot_s(pal2->nsb,lc_istr_prot(sxi,j,pcode1,pal1));
     nstrcat_prot_s(pal2->nsb,lc_istr_prot(sxi,k,pcode1,pal1));
   }
  if (smrep->s_or_m == 'm')
    {nstrcpy_prot_s(pal2->nsa,lc_istr_prot(sxi,i,pcode1,pal1));
     nstrcat_prot_s(pal2->nsa,lc_istr_prot(sxi,j,pcode1,pal1));
     nstrcpy_prot_s(pal2->nsb,lc_istr_prot(sxi,k,pcode1,pal1));
    }

 if (db_level > 1)
   {printf("%s un-aligned phone strings:\n",pdb);
    dump_int_alignment_prot(pal2);
   }

   smrep->pdist_sm = aldist2_prot(pal2,wod2_prot,dont_return_alignment,pdummy,perr);
   if (*perr > 0)
     {fprintf(stderr,"*ERR: aldist2_prot returns err code=%d\n",*perr);
      goto RETURN;
     }

if (db_level > 0) printf("%s pdist_sm=%d\n",pdb,smrep->pdist_sm);
if (db_level > 1)
 {aldist2_prot(pal2,wod2_prot,return_alignment,palx,perr);
  printf("%s aligned phone strings:\n",pdb);
  dump_int_alignment_prot(palx);
 }

/* compute pdist not hypothesizing split or merge */
if (db_level > 0) printf("%s computing Dph *not* hypothesizing s/m.\n",pdb);
  if (smrep->s_or_m == 's')
    {if (smrep->l_or_r == 'l')
       {/* i->j + 0->k */
        nstrcpy_prot_s(pal2->nsa,lc_istr_prot(sxi,i,pcode1,pal1));
        nstrcpy_prot_s(pal2->nsb,lc_istr_prot(sxi,j,pcode1,pal1));
        smrep->pdist = aldist2_prot(pal2,wod2_prot,dont_return_alignment,pdummy,perr);
        nstrcpy_prot_s(pal2->nsa,lc_istr_prot(sxi,0,pcode1,pal1));
        nstrcpy_prot_s(pal2->nsb,lc_istr_prot(sxi,k,pcode1,pal1));
        smrep->pdist += aldist2_prot(pal2,wod2_prot,dont_return_alignment,pdummy,perr);
       }
     if (smrep->l_or_r == 'r')
       {/* 0->j + i->k */
        nstrcpy_prot_s(pal2->nsa,lc_istr_prot(sxi,0,pcode1,pal1));
        nstrcpy_prot_s(pal2->nsb,lc_istr_prot(sxi,j,pcode1,pal1));
        smrep->pdist = aldist2_prot(pal2,wod2_prot,dont_return_alignment,pdummy,perr);
        nstrcpy_prot_s(pal2->nsa,lc_istr_prot(sxi,i,pcode1,pal1));
        nstrcpy_prot_s(pal2->nsb,lc_istr_prot(sxi,k,pcode1,pal1));
        smrep->pdist += aldist2_prot(pal2,wod2_prot,dont_return_alignment,pdummy,perr);
       }
    }
  if (smrep->s_or_m == 'm')
    {if (smrep->l_or_r == 'l')
       {/* i->k + j->0 */
        nstrcpy_prot_s(pal2->nsa,lc_istr_prot(sxi,i,pcode1,pal1));
        nstrcpy_prot_s(pal2->nsb,lc_istr_prot(sxi,k,pcode1,pal1));
        smrep->pdist = aldist2_prot(pal2,wod2_prot,dont_return_alignment,pdummy,perr);
        nstrcpy_prot_s(pal2->nsa,lc_istr_prot(sxi,j,pcode1,pal1));
        nstrcpy_prot_s(pal2->nsb,lc_istr_prot(sxi,0,pcode1,pal1));
        smrep->pdist += aldist2_prot(pal2,wod2_prot,dont_return_alignment,pdummy,perr);
       }
     if (smrep->l_or_r == 'r')
       {/* i->0 + j->k*/
        nstrcpy_prot_s(pal2->nsa,lc_istr_prot(sxi,i,pcode1,pal1));
        nstrcpy_prot_s(pal2->nsb,lc_istr_prot(sxi,0,pcode1,pal1));
        smrep->pdist = aldist2_prot(pal2,wod2_prot,dont_return_alignment,pdummy,perr);
        nstrcpy_prot_s(pal2->nsa,lc_istr_prot(sxi,j,pcode1,pal1));
        nstrcpy_prot_s(pal2->nsb,lc_istr_prot(sxi,k,pcode1,pal1));
        smrep->pdist += aldist2_prot(pal2,wod2_prot,dont_return_alignment,pdummy,perr);
       }
    }

if (db_level > 0) printf("%s pdist=%d\n",pdb,smrep->pdist);

  smrep->fom = ((double)smrep->pdist_sm == 0) ? HUGE_VAL : 
      ((double)smrep->pdist)/((double)smrep->pdist_sm);

if (db_level > 0) printf("%s figure_of_merit=%f\n",pdb,smrep->fom);

RETURN:
  dealloc_prot_int_str_guts(sxi);
  dealloc_prot_chr_str_guts(sxdb);
  free_al_int_prot(pal2);
  free_al_int_prot(palx);
db_leave_msg(proc,0); /* debug only */
  return;
 } /* end fcn rate_sm_prot() */



/******************************************************/
/*  fcn interchange_entries(table,i,j)                */
/*  interchanges entries i and j in  *table.          */
/******************************************************/

static void interchange_entries(SM_TAB_STR2 *table, int i, int j)
{SM_ELEMENT2 temp_entry;
  temp_entry = table->entry[i];
  table->entry[i] = table->entry[j];
  table->entry[j] = temp_entry;
 }

/********************************************/
/*  void sort_sm_by_fom(smtab)              */
/*  Sorts the sm table *smtab by fom        */
/*  Uses a simple sort that is just fine if */
/*  file is short or already almost sorted. */
/********************************************/

static void sort_sm_by_fom(SM_TAB_STR2 *smtab)
{int i,j;
  for(i = 0; i < smtab->nsaved - 1; i++)
    {for (j = i + 1; j < smtab->nsaved; j++)
       {if (smtab->entry[j].fom > smtab->entry[i].fom)
          interchange_entries(smtab,i,j);
 }  }  }
/* end function sort_sm_by_fom() */

/********************************************/
/*  void sort_sm_by_iloc(smtab)             */
/*  Sorts the sm table *smtab into          */
/* descending order by iloc.                */
/*  Uses a simple sort that is just fine if */
/*  file is short or already almost sorted. */
/********************************************/

void sort_sm_by_iloc(SM_TAB_STR2 *smtab)
{int i,j;
  for(i = 0; i < smtab->nsaved - 1; i++)
    {for (j = i + 1; j < smtab->nsaved; j++)
       {if (smtab->entry[j].iloc > smtab->entry[i].iloc)
          interchange_entries(smtab,i,j);
 }  }  }
/* end function sort_sm_by_iloc() */


/**********************************************/
/*  void save_sm(smrep,smtab)                 */
/*  Stores the s/m entry *smrep into the s/m  */
/* table *smtab                               */
/**********************************************/

static void save_sm(SM_ELEMENT2 *smrep, SM_TAB_STR2 *smtab)
{char *proc = "save_sm";
 db_enter_msg(proc,0); /* debug only */
  if (smtab->nsaved < MAX_SMTAB_ENTRIES)
    {smtab->nsaved += 1;
     smtab->entry[smtab->nsaved - 1] = *smrep;
if (db_level > 0) printf("%snew nsaved = %d\n",pdb,smtab->nsaved);
    }
  else
    {fprintf(stderr,"*ERR:%s: SMTAB overflow.\n",proc);
    }
 db_leave_msg(proc,0); /* debug only */
 }
/* end function save_sm() */


/********************************************/
/*  void dump_smtab(smtab)                  */
/*  dumps the split/merge info in *smtab.   */
/********************************************/
void dump_smtab(SM_TAB_STR2 *smtab)
 {int ix;
  SM_ELEMENT2 x;
  fprintf(stdout,"\n");
  fprintf(stdout," DUMP OF SPLIT/MERGE TABLE INFO\n");
  fprintf(stdout," nsaved = %d\n",smtab->nsaved);
  fprintf(stdout," nover  = %d\n",smtab->nover);
  if (smtab->nsaved > 0)
    {fprintf(stdout,
       "             figure\n");
     fprintf(stdout,
       " #    freq  of merit  pdist  pdist_sm  iloc    i     j     k  s/m l/r\n");
     for (ix = 0; ix < smtab->nsaved; ix++)
       {x = smtab->entry[ix];
        fprintf(stdout,"%2d %7lu  %7.3f %6d %6d    %5d %5d %5d %5d   %c   %c\n",
           ix,x.frequency,x.fom,x.pdist,x.pdist_sm,x.iloc,
           x.ival,x.jval,x.kval,x.s_or_m,x.l_or_r);
    }  }
  fprintf(stdout,"\n");
 }
/* end function dump_smtab() */


static void find_sm2_prot(ALIGNMENT_INT_PROT *pal, double fom_threshold, SM_TAB_STR2 *smtab)
/********************************************************************/
/*  looks in *pal for splits/merges to store in  s/m table *smtab.  */
/********************************************************************/
{int ix; SM_ELEMENT2 smrep;
 char *proc = "find_sm2_prot";
db_enter_msg(proc,0); /* debug only */
if (db_level > 0) printf("%s fom_threshold='%f'\n",pdb,fom_threshold);
/* initialize */
  smrep.pdist = 0;
  smrep.pdist_sm = 0;
  smrep.frequency = 0;
  smtab->nsaved = 0;
  smtab->nover = 0;
/* check for splits */
  for (ix=1; ix <= pal->nsa->str[0]; ix++)
    {if (ix > 1)   /*check for left splits and merges */
       {smrep.l_or_r = 'l';
        if (pal->nsa->str[ix] == 0)  /* split */
          {smrep.s_or_m = 's';
if (db_level > 1) printf("%s potential split @ix=%d\n",pdb,ix);
           if ((pal->nsa->str[ix-1] != 0)&&(pal->nsb->str[ix-1] != 0))
             {smrep.ival = pal->nsa->str[ix-1];
              smrep.jval = pal->nsb->str[ix-1];
              smrep.kval = pal->nsb->str[ix];
              smrep.iloc = ix-1;
              rate_sm_prot(&smrep,pal);
              if (smrep.fom > fom_threshold) save_sm(&smrep,smtab);
          }  }
        if (pal->nsb->str[ix] == 0)  /* merge */
          {smrep.s_or_m = 'm';
if (db_level > 1) printf("%s potential merge @ix=%d\n",pdb,ix);
           if ((pal->nsa->str[ix-1] != 0)&&(pal->nsb->str[ix-1] != 0))
             {smrep.ival = pal->nsa->str[ix-1];
              smrep.jval = pal->nsa->str[ix];
              smrep.kval = pal->nsb->str[ix-1];
              smrep.iloc = ix-1;
              rate_sm_prot(&smrep,pal);
              if (smrep.fom > fom_threshold) save_sm(&smrep,smtab);
       }  }  }
     if (ix < pal->nsa->str[0])   /*check for right splits and merges */
       {smrep.l_or_r = 'r';
        if (pal->nsa->str[ix] == 0)  /* split */
          {smrep.s_or_m = 's';
           if ((pal->nsa->str[ix+1] != 0)&&(pal->nsb->str[ix+1] != 0))
             {smrep.ival = pal->nsa->str[ix+1];
              smrep.jval = pal->nsb->str[ix];
              smrep.kval = pal->nsb->str[ix+1];
              smrep.iloc = ix+1;
              rate_sm_prot(&smrep,pal);
              if (smrep.fom > fom_threshold) save_sm(&smrep,smtab);
          }  }
        if (pal->nsb->str[ix] == 0)  /* merge */
          {smrep.s_or_m = 'm';
           if ((pal->nsa->str[ix+1] != 0)&&(pal->nsb->str[ix+1] != 0))
             {smrep.ival = pal->nsa->str[ix];
              smrep.jval = pal->nsa->str[ix+1];
              smrep.kval = pal->nsb->str[ix+1];
              smrep.iloc = ix;
              rate_sm_prot(&smrep,pal);
              if (smrep.fom > fom_threshold) save_sm(&smrep,smtab);
    }  }  }  }
db_leave_msg(proc,0); /* debug only */
  return;
 }
/* end function find_sm2_prot() */



/****************************************************/
/*  struct INTERVAL1 limits(smrep)                  */
/* Returns the interval of indexes from *smrep.     */
/****************************************************/

static struct INTERVAL1 limits(SM_ELEMENT2 *smrep)
{char *proc = "limits";
  struct INTERVAL1 x;
db_enter_msg(proc,1); /* debug only */
  if (smrep->s_or_m == 'm')
    {x.l1 = smrep->iloc;
     x.l2 = smrep->iloc + 1;
    }
  else
    {if (smrep->l_or_r == 'l')
       {x.l1 = smrep->iloc;
        x.l2 = smrep->iloc + 1;
       }
     else
       {x.l1 = smrep->iloc - 1;
        x.l2 = smrep->iloc;
    }  }
db_leave_msg(proc,1); /* debug only */
  return x;
 }



/****************************************************/
/*  boolean sm_overlap(i,j,smtab)                   */
/*  Determines if there is an overlap between       */
/* entries i and j in the split/merge table *smtab. */
/****************************************************/

static boolean sm_overlap(int i, int j, SM_TAB_STR2 *smtab)
{char *proc = "sm_overlap";
  boolean ovl;
  SM_ELEMENT2 *ismrep,*jsmrep;
db_enter_msg(proc,0); /* debug only */
/* initialize */
if (db_level > 0) printf("%s checking i=%d,j=%d for overlap\n",pdb,i,j);
  ovl = F;
  ismrep = (SM_ELEMENT2*)&(smtab->entry[i]);
  jsmrep = (SM_ELEMENT2*)&(smtab->entry[j]);
  if (overlap1(limits(ismrep),limits(jsmrep)) > 0) ovl = T;
  else                                             ovl = F;
if (db_level > 0) printf("%s at exit, overlap = %s\n",pdb,bool_print(ovl));
db_leave_msg(proc,0); /* debug only */
  return ovl;
 }


  int sm_correction2_prot(ALIGNMENT_INT_PROT *pt1, double fom_threshold,
        SM_TAB_STR2 *smtab, int *perr)
 /**********************************************************************/
 /*                                                                    */
 /*    Determines the correction to the alignment distance of the      */
 /* alignment in *pt1 that should be made on account of splits and     */
 /* merges.  Returns this correction and leaves the s/m's in the       */
 /* split/merge table *smtab.  Only s/m's with a figure of merit       */
 /* greater than <fom_threshold> are kept.                             */
 /*    To get the s/m's, this version uses find_sm2(), which calls     */
 /* rate_sm(), which uses aldist2_prot() to calculate the distance     */
 /* between the lower-code versions of the symbols in *pt1.            */
 /* If the integers in the strings in *pt1 are greater than the        */
 /* highest code in pt1's pcode, then they represent entries in the    */
 /* auxiliary table auxtab[], which represents a list of pcode symbols */
 /* to be regarded as one.                                             */
 /*    This version DOES zero the smtab but not the auxtab.            */
 /*                                                                    */
 /*   *perr = 0 means a.o.k.                                           */
 /*   error codes:                                                     */
 /*   11:invalid input parameters                                      */
 /*                                                                    */
 /**********************************************************************/

   {
/* data: */
    char *proc = "sm_correction2_prot";
    int correction,i,j;
    SM_TAB_STR2 smtabxx, *smtabx = &smtabxx;
    boolean sm_used[MAX_SMTAB_ENTRIES], conflict;
/* code: */

 /**** start debug ****/
db_enter_msg(proc,0); /* debug only */
if (db_level > 0 )
   {printf("%son entry, input alignment pt1 is:\n",pdb);
    dump_int_alignment4_prot(pt1);
   }
 /**** debug ****/

 /* initialize output variables */
  *perr=0;
  correction = 0;
  smtab->nsaved = 0;
  smtab->nover = 0;
/* get the preliminary list of s/m's */
  find_sm2_prot(pt1,fom_threshold,smtabx);
  sort_sm_by_fom(smtabx);
if (db_level > 0)
 {printf("%s preliminary table of possible s/ms, sorted by FOM:\n",pdb);
  dump_smtab(smtabx);
 }
  if (smtabx->nsaved > 0)
    {/* mark all sm candidates as unused */

if (db_level > 0)
printf("%s selecting highest FOM not conflicting already selected\n",pdb);

     for (i=0; i < smtabx->nsaved; i++) sm_used[i] = F;
     /* go down the list, using the highest one that hasn't been
        used yet and doesn't conflict (overlap) with one that has
        already been chosen (used). */
     for (i=0; i < smtabx->nsaved; i++)
       {
if (db_level > 0) printf("%s checking sm #i=%d\n",pdb,i);
        if (!sm_used[i])
          {conflict = F;
if (db_level > 0) printf("%s it's not used yet (redundant check)\n",pdb);
           for (j=0; (!conflict)&&(j < i); j++)
              if (sm_used[j]) conflict = sm_overlap(i,j,smtabx);
           if (!conflict)
             {save_sm(&(smtabx->entry[i]),smtab);
              sm_used[i] = T;
              correction += (smtabx->entry[i].pdist
                             -smtabx->entry[i].pdist_sm);
    }  }  }  }

/**** de-bug ****/
 if (db_level > 0) printf("%s correction=%d\n",pdb,correction);
if (db_level > 0)
 {printf("%s on exit, selected s/ms are:\n",pdb);
  dump_smtab(smtab);
 }
 db_leave_msg(proc,0); /* debug only */
/**** de-bug ****/

  return correction;
  } /* end of function "sm_correction2_prot" */




static int add_to_auxtab_prot(int i, int j, ALIGNMENT_INT_PROT *pal)
 /**********************************************************************/
 /*                                                                    */
 /* Adds the entry (i+j) to the auxiliary symbol table pal->auxtab[],  */
 /* returning the index of the new entry.                              */
 /* NOTE: i and j may themselves be either pcode symbols or symbols in */
 /* pal->auxtab[].  Returns 0 on ovf.                                  */
 /* (If i or j is an entry in the auxtab[], as indicated by being a    */
 /* value greater than pal->pcset->pctab_length, the ith or jth entry  */
 /* is just added to; otherwise, a new entry is created and *pnaux is  */
 /*  bumped.                                                           */
 /*                                                                    */
 /**********************************************************************/

  {
/* data: */
   char *proc = "add_to_auxtab_prot";
   int iaux,jaux,kaux,iret, ix;
   PROTECTED_INT_STR *sintp;
   PROTECTED_INT_STR **new_auxtab; /* dynamically allocated */
/* code: */
 db_enter_msg(proc,1); /* debug only */
   if (i > pal->pcset->pctab_length)
     {/* i is an auxiliary symbol */
      iaux = i - pal->pcset->pctab_length;
      if (iaux > pal->naux) fatal_error(proc,"bad iaux > pal->naux",iaux);
      if (j > pal->pcset->pctab_length)
        {/* j is an auxiliary symbol */
         jaux = j - pal->pcset->pctab_length;
         if (jaux > pal->naux) fatal_error(proc,"bad jaux > pal->naux",jaux);
         /* add aux j onto tail of aux i */
         nstrcat_prot_p(pal->auxtab[iaux],pal->auxtab[jaux]);
         iret = iaux;
         /* delete j from auxtab */
         destroy_prot_int_str(pal->auxtab[jaux]);
         for (kaux=jaux+1; kaux<=pal->naux; kaux++)
           {/*free auxtab[kaux-1]?? */
            pal->auxtab[kaux-1] = pal->auxtab[kaux];
           }
         pal->naux -= 1;
        }
      else
        {/* j is NOT an auxiliary symbol */
         /* add word j onto tail of aux i */
         nstrcat_prot_i(pal->auxtab[iaux],j);
         iret = iaux;
     }  }
   else
     {/* i is NOT an auxiliary symbol */
      if (j > pal->pcset->pctab_length)
        {/* j is an auxiliary symbol */
         /* add word i onto head of aux j */
         jaux = j - pal->pcset->pctab_length;
         if (jaux > pal->naux) fatal_error(proc,"bad jaux > pal->naux",jaux);
         sintp = (PROTECTED_INT_STR *) malloc_safe(sizeof(PROTECTED_INT_STR),proc);
         sintp = create_prot_int_str(6);
         nstrcpy_prot_i(sintp,i);
         nstrcat_prot_p(sintp,pal->auxtab[jaux]);
         destroy_prot_int_str(pal->auxtab[jaux]);
         pal->auxtab[jaux] = sintp;
         iret = jaux;
        }
      else
        {/* neither i nor j is an aux symbol; make new auxtab entry */
         pal->naux += 1;
         if (pal->naux > pal->max_aux) /* make new entry for word i + word j */
           {/* expand auxtab */
            pal->max_aux += 1;
            new_auxtab = (PROTECTED_INT_STR**)calloc_safe(pal->max_aux+1,sizeof(PROTECTED_INT_STR*),proc);
if (db_level > 3) printf("%s allocated new_auxtab at %x\n",pdb,(int)new_auxtab);
            for (ix=1; ix <= pal->naux-1; ix++) new_auxtab[ix] = pal->auxtab[ix];
if (db_level > 3) printf("%s freeing %s->auxtab at %x\n",pdb,pal->id->str,(int)pal->auxtab);
            free((char*)pal->auxtab);
if (db_level > 3) printf("%s setting %s->auxtab to new_auxtab (%x)\n",pdb,pal->id->str,(int)new_auxtab);
            pal->auxtab = new_auxtab;
           }
         sintp = create_prot_int_str(6);
         nstrcpy_prot_i(sintp,i);
         nstrcat_prot_i(sintp,j);
         pal->auxtab[pal->naux] = sintp;
         iret = pal->naux;
     }  }
 
 db_leave_msg(proc,1); /* debug only */
   return iret;
  } /* end of function "add_to_auxtab_prot" */



void put_sm_into_aln_prot(ALIGNMENT_INT_PROT *pal, SM_TAB_STR2 *smtab, int *perr)
 /**********************************************************************/
 /*                                                                    */
 /*    Puts the splits/merges in smtab into the alignment *pal and the */
 /* auxiliary table pal->auxtab[] (and pal->naux).                     */
 /*   *perr = 0 means a.o.k.                                           */
 /*   error codes:                                                     */
 /*   11:invalid input parameters                                      */
 /*                                                                    */
 /**********************************************************************/
  {
/* data: */
   char *proc = "put_sm_into_aln";
   SM_ELEMENT2 smrepx, *smx = &smrepx;
   int ix,k,iaux;
/* code: */

 /**** start debug ****/
db_enter_msg(proc,0); /* debug only */
if (db_level > 0 )
   {printf("%s on entry, the pcode is '%s'\n",pdb,(pal->pcset)->name);
    dump_int_alignment4_prot(pal);
    printf("%s smtab->nsaved=%d\n",pdb,smtab->nsaved);
    printf("%s and the smtab is:\n",pdb);
    dump_smtab(smtab);
    printf("%s and the auxtab is:\n",pdb);
    dump_auxtab_prot(pal);
   }
 /**** debug ****/

 /* initialize */
   *perr=0;
/* check input data */
 /* NOTE - SMTAB ENTRIES MUST BE IN DECREASING ORDER BY ILOC */
    for (ix = 0; ix < smtab->nsaved - 1; ix++)
      if (smtab->entry[ix].iloc < smtab->entry[ix+1].iloc)
        {fprintf(stdout,
          "*ERR:%s: smtab not in decreasing order by iloc.\n",proc);
         *perr = 11; goto RETURN;
        }
/* loop on s/m's */
   for (ix = 0; ix < smtab->nsaved; ix++)
     {*smx = smtab->entry[ix];
if (db_level > 0) printf("%s processing smtab entry %d\n",pdb,ix);
      if (smx->s_or_m == 's') /* SPLIT */
        {/* combine j and k into one aux symbol */
         iaux = add_to_auxtab_prot(smx->jval,smx->kval,pal);
         if (iaux > 0)
           {/* replace HYP jval i aln with iaux + pal->pcset->pctab_length*/
            /* and delete REF null and HYP kval         */
            if (smx->l_or_r == 'l')  /* LEFT */
              {pal->nsb->str[smx->iloc] = iaux + pal->pcset->pctab_length;
               for (k=smx->iloc+2; k <= pal->nsb->str[0]; k++)
                 {pal->nsa->str[k-1]  = pal->nsa->str[k];
                  pal->nsb->str[k-1]  = pal->nsb->str[k];
              }  }
            else                     /* RIGHT */
              {pal->nsb->str[smx->iloc - 1] = iaux + pal->pcset->pctab_length;
               for (k=smx->iloc; k <= pal->nsa->str[0]; k++)
                 {pal->nsa->str[k-1] = pal->nsa->str[k];
                 } 
               for (k=smx->iloc + 1; k <= pal->nsb->str[0]; k++)
                 {pal->nsb->str[k-1] = pal->nsb->str[k];
           }  }  }
         else
           {fprintf(stderr,"*ERR:%s: auxtab ovf.\n",proc);
            *perr = 11; goto RETURN;
        }  }
      else     /* MERGE */
        {/* combine i and j into one aux symbol */
         iaux = add_to_auxtab_prot(smx->ival,smx->jval,pal);
         if (iaux > 0)
           {/* replace REF ival in aln with iaux + pal->pcset->pctab_length */
            /* and delete HYP null and REF jval         */
            if (smx->l_or_r == 'l')  /* LEFT */
              {pal->nsa->str[smx->iloc] = iaux + pal->pcset->pctab_length;
               for (k=smx->iloc+2; k <= pal->nsb->str[0]; k++)
                 {pal->nsa->str[k-1]  = pal->nsa->str[k];
                  pal->nsb->str[k-1]  = pal->nsb->str[k];
              }  }
            else                     /* RIGHT */
              {pal->nsa->str[smx->iloc] = iaux + pal->pcset->pctab_length;
               for (k=smx->iloc+2; k <= pal->nsa->str[0]; k++)
                 {pal->nsa->str[k-1] = pal->nsa->str[k];
		 }
               for (k=smx->iloc+1; k <= pal->nsb->str[0]; k++)
                 {pal->nsb->str[k-1] = pal->nsb->str[k];
           }  }  }
         else
           {fprintf(stderr,"*ERR:%s: auxtab ovf.\n",proc);
            *perr = 11; goto RETURN;
        }  }
      pal->nsa->str[0] -= 1;
      pal->nsb->str[0] -= 1;
     }  /* END OF LOOP OVER SMTAB */
RETURN:

if (db_level > 0)
   {printf("%s on exit,\n",pdb);
    dump_int_alignment4_prot(pal);
    printf("%s and the auxtab is:\n",pdb);
    dump_auxtab_prot(pal);
  }

 db_leave_msg(proc,0); /* debug only */
   return;
  } /* end of function "put_sm_into_aln_prot" */

/* end file sm_pkg1pr.c */
