Example #1
0
static void remap_NoCutList(AjPFile outfile, const AjPTable hittable,
			    AjBool html, const AjPStr enzymes, AjBool blunt,
			    AjBool sticky, ajuint sitelen, AjBool commercial,
			    AjBool ambiguity, AjBool limit,
			    const AjPTable retable)
{

    /* for iterating over hittable */
    PValue value;
    void **keyarray = NULL;			/* array for table */
    void **valarray = NULL;			/* array for table */
    ajint i;

    /* list of enzymes that cut */
    AjPList cutlist;
    AjIList citer;			/* iterator for cutlist */
    AjPStr cutname = NULL;
    AjBool found;

    /* for parsing value->iso string */
    AjPStrTok tok;
    char tokens[] = " ,";
    AjPStr code = NULL;
    const char *p;

    /* for reading in enzymes names */
    AjPFile enzfile = NULL;
    AjPStr *ea;
    ajint ne;				/* number of enzymes */
    AjBool isall = ajTrue;

    /* list of enzymes that don't cut */
    AjPList nocutlist;
    AjIList niter;			/* iterator for nocutlist */
    AjPStr nocutname = NULL;

    /* count of rejected enzymes not matching criteria */
    ajint rejected_count = 0;

    EmbPPatRestrict enz;

    /* for renaming preferred isoschizomers */
    AjPList newlist;

     /*
     **
     ** Make a list of enzymes('cutlist') that hit
     ** including the isoschizomer names
     **
     */
    ajDebug("Make a list of all enzymes that cut\n");


    cutlist   = ajListstrNew();
    nocutlist = ajListstrNew();


    ajTableToarrayKeysValues(hittable, &keyarray, &valarray);
    for(i = 0; keyarray[i]; i++)
    {
        value = (PValue) valarray[i];
        cutname = ajStrNew();
        ajStrAssignRef(&cutname, keyarray[i]);
        ajListstrPushAppend(cutlist, cutname);

        /* Add to cutlist all isoschizomers of enzymes that cut */
        ajDebug("Add to cutlist all isoschizomers of enzymes that cut\n");

        /* start token to parse isoschizomers names */
        tok = ajStrTokenNewC(value->iso,  tokens);
        while(ajStrTokenNextParseC(&tok, tokens, &code))
        {
            cutname = ajStrNew();
            ajStrAssignS(&cutname, code);
            ajListstrPushAppend(cutlist, cutname);
        }
        ajStrTokenDel(&tok);
    }
    ajStrDel(&code);
    AJFREE(keyarray);
    AJFREE(valarray);



     /*
     ** Read in list of enzymes ('nocutlist') - either all or
     ** the input enzyme list.
     ** Exclude those that don't match the selection criteria - count these.
     */

    ajDebug("Read in a list of all input enzyme names\n");

    ne = 0;
    if(!enzymes)
	isall = ajTrue;
    else
    {
	/* get input list of enzymes into ea[] */
	ne = ajArrCommaList(enzymes, &ea);
	if(ajStrMatchCaseC(ea[0], "all"))
	    isall = ajTrue;
	else
	{
	    isall = ajFalse;
	    for(i=0; i<ne; ++i)
		ajStrRemoveWhite(&ea[i]);
	}
    }

    enzfile = ajDatafileNewInNameC(ENZDATA);

    /* push all enzyme names without the required criteria onto nocutlist */

    enz = embPatRestrictNew();
    while(!ajFileIsEof(enzfile))
    {
        if(!embPatRestrictReadEntry(enz, enzfile))
	    continue;

         /* 
	 ** If user entered explicit enzyme list, then check to see if
	 ** this is one of that explicit list 
	 */
        if(!isall)
	{
            found = AJFALSE;
            for(i=0; i<ne; ++i)
                if(ajStrMatchCaseS(ea[i], enz->cod))
		{
		    found = AJTRUE;
                    break;
                }

	    if(!found)			/* not in the explicit list */
		continue;

	    ajDebug("RE %S is in the input explicit list of REs\n", enz->cod);
	}

	/* ignore ncuts==0 as they are unknown */
	if(!enz->ncuts)
	{
	    /* number of cut positions */
            ajDebug("RE %S has an unknown number of cut positions\n",
		    enz->cod);
	    continue;
	}
        ajDebug("RE %S has a known number of cut sites\n", enz->cod);

	if(enz->len < sitelen)
	{
	    /* recognition site length */
            ajDebug("RE %S does not have a long enough recognition site\n", 
		    enz->cod);
	    rejected_count++;
	    continue;
	}

	if(!blunt && enz->blunt)
	{
	    /* blunt/sticky */
            ajDebug("RE %S is blunt\n", enz->cod);
	    rejected_count++;
	    continue;
	}

	if(!sticky && !enz->blunt)
	{
	    /* blunt/sticky */
            ajDebug("RE %S is sticky\n", enz->cod);
	    rejected_count++;
	    continue;
	}

	/* commercially available enzymes have uppercase patterns */
	p = ajStrGetPtr(enz->pat);

         /* 
	 ** The -commercial qualifier is only used if we are searching
	 ** through 'all' of the REBASE database - if we have specified an
	 ** explicit list of enzymes then they are searched for whether or
	 ** not they are commercially available
	 */
	if((*p >= 'a' && *p <= 'z') && commercial && isall)
	{
            ajDebug("RE %S is not commercial\n", enz->cod);
	    rejected_count++;
	    continue;
        }

	if(!ambiguity && remap_Ambiguous(enz->pat)) {
	    ajDebug("RE %S is ambiguous\n", enz->cod);
	    rejected_count++;
	    continue;	
	}

        ajDebug("RE %S matches all required criteria\n", enz->cod);

        code = ajStrNew();
	ajStrAssignS(&code, enz->cod);
	ajListstrPushAppend(nocutlist, code);
    }
    embPatRestrictDel(&enz);
    ajFileClose(&enzfile);


    for(i=0; i<ne; ++i)
	if(ea[i])
	    ajStrDel(&ea[i]);

    if(ne)
	AJFREE(ea);

    /*
     ** Change names of enzymes in the non-cutter list
     ** to that of preferred (prototype) 
     ** enzyme name so that the isoschizomers of cutters
     ** will be removed from the 
     ** non-cutter list in the next bit.
     ** Remove duplicate prototype names.
     */
    if(limit)
    {
        newlist = ajListstrNew();
        remap_RenamePreferred(nocutlist, retable, newlist);
        ajListstrFreeData(&nocutlist);
        nocutlist = newlist;
        ajListSortUnique(nocutlist, remap_cmpcase, remap_strdel);
    }


     /*
     ** Iterate through the list of input enzymes removing those that are in
     ** the cutlist.
     */

    ajDebug("Remove from the nocutlist all enzymes and isoschizomers "
	    "that cut\n");

     /*
     **  This steps down both lists at the same time, comparing names and
     **  iterating to the next name in whichever list whose name compares
     **  alphabetically before the other.  Where a match is found, the
     **  nocutlist item is deleted.
     */

    ajListSort(nocutlist, remap_cmpcase);
    ajListSort(cutlist, remap_cmpcase);

    citer = ajListIterNewread(cutlist);
    niter = ajListIterNew(nocutlist);

    /*
       while((cutname = (AjPStr)ajListIterGet(citer)) != NULL)
       ajDebug("dbg cutname = %S\n", cutname);
       */

    nocutname = (AjPStr)ajListIterGet(niter);
    cutname   = (AjPStr)ajListIterGet(citer);

    ajDebug("initial cutname, nocutname: '%S' '%S'\n", cutname, nocutname);

    while(nocutname != NULL && cutname != NULL)
    {
	i = ajStrCmpCaseS(cutname, nocutname);
	ajDebug("compare cutname, nocutname: %S %S ", cutname, nocutname);
	ajDebug("ajStrCmpCase=%d\n", i);
	if(i == 0)
	{
	    /* match - so remove from nocutlist */
	    ajDebug("ajListstrRemove %S\n", nocutname);
	    ajListstrIterRemove(niter);
	    nocutname = (AjPStr)ajListIterGet(niter);
	     /* 
	     ** Don't increment the cutname list pointer here
	     ** - there may be more than one entry in the nocutname
	     ** list with the same name because we have converted 
	     ** isoschizomers to their preferred name
	     */
	    /* cutname = (AjPStr)ajListIterGet(citer); */
	}
	else if(i == -1)
	    /* cutlist name sorts before nocutlist name */
	    cutname = (AjPStr)ajListIterGet(citer);
	else if(i == 1)
	    /* nocutlist name sorts before cutlist name */
	    nocutname = (AjPStr)ajListIterGet(niter);
    }

    ajListIterDel(&citer);
    ajListIterDel(&niter);
    ajListstrFreeData(&cutlist);


     /* Print the resulting list of those that do not cut*/

    ajDebug("Print out the list\n");

    /* print the title */
    if(html)
	ajFmtPrintF(outfile, "<H2>");
    ajFmtPrintF(outfile, "\n\n# Enzymes that do not cut\n\n");

    if(html)
	ajFmtPrintF(outfile, "</H2>\n");

    if(html)
	ajFmtPrintF(outfile, "<PRE>");

    /*  ajListSort(nocutlist, ajStrVcmp);*/
    niter = ajListIterNewread(nocutlist);
    i = 0;
    while((nocutname = (AjPStr)ajListIterGet(niter)) != NULL)
    {
	ajFmtPrintF(outfile, "%-10S", nocutname);
	/* new line after every 7 names printed */
	if(i++ == 7)
	{
	    ajFmtPrintF(outfile, "\n");
	    i = 0;
	}
    }
    ajListIterDel(&niter);


    /* end the output */
    ajFmtPrintF(outfile, "\n");
    if(html) {ajFmtPrintF(outfile, "</PRE>\n");}



     /*
     ** Print the count of rejected enzymes
     ** N.B. This is the count of ALL rejected enzymes including all
     ** isoschizomers
     */

    if(html)
        ajFmtPrintF(outfile, "<H2>");
    ajFmtPrintF(outfile,
		"\n\n# No. of cutting enzymes which do not match the\n"
		"# SITELEN, BLUNT, STICKY, COMMERCIAL, AMBIGUOUS criteria\n\n");
    if(html)
	ajFmtPrintF(outfile, "</H2>\n");
    ajFmtPrintF(outfile, "%d\n", rejected_count);

    ajDebug("Tidy up\n");
    ajListstrFreeData(&nocutlist);
    ajListstrFreeData(&cutlist);

    return;
}
Example #2
0
EnsPIntron ensIntronNewExons(EnsPExon exon1, EnsPExon exon2)
{
    ajint strand = 0;
    
    ajuint start = 0;
    ajuint end   = 0;
    
    AjPStr seqname1 = NULL;
    AjPStr seqname2 = NULL;
    
    EnsPFeature feature  = NULL;
    EnsPFeature feature1 = NULL;
    EnsPFeature feature2 = NULL;
    
    EnsPIntron intron = NULL;
    
    EnsPSlice slice1 = NULL;
    EnsPSlice slice2 = NULL;
    
    /*
     ajDebug("ensIntronNew\n"
	     "  exon1 %p\n"
	     "  exon2 %p\n",
	     exon1,
	     exon2);
     
     ensExonTrace(exon1, 1);
     
     ensExonTrace(exon2, 1);
     */
    
    if(!exon1)
	return NULL;
    
    if(!exon2)
	return NULL;
    
    feature1 = ensExonGetFeature(exon1);
    feature2 = ensExonGetFeature(exon2);
    
    slice1 = ensFeatureGetSlice(feature1);
    slice2 = ensFeatureGetSlice(feature2);
    
    seqname1 = ensFeatureGetSequenceName(feature1);
    seqname2 = ensFeatureGetSequenceName(feature2);
    
    /* Both Exons have to be on the same Slice or sequence. */
    
    if(slice1 && slice2 && (!ensSliceMatch(slice1, slice2)))
    {
	ajDebug("ensIntronNewExons got Exons on different Slices.\n");
	
	return NULL;
    }
    else if(seqname1 && seqname2 && (!ajStrMatchCaseS(seqname1, seqname2)))
    {
	ajDebug("ensIntronNewExons got Exons on different sequence names.\n");
	
	return NULL;
    }
    else
    {
	ajDebug("ensIntronNewExons got Exons on Slice and sequence names.\n");
	
	return NULL;
    }
    
    if(ensFeatureGetStrand(feature1) != ensFeatureGetStrand(feature2))
    {
	ajDebug("ensIntronNewExons got Exons on different strands.\n");
	
	return NULL;
    }
    
    if(ensFeatureGetStrand(feature1) >= 0)
    {
	start = ensFeatureGetEnd(feature1) + 1;
	
	end = ensFeatureGetStart(feature2) - 1;
    }
    else
    {
	start = ensFeatureGetEnd(feature2) + 1;
	
	end = ensFeatureGetStart(feature1) - 1;
    }
    
    if(start > (end + 1))
    {
	ajDebug("ensIntronNewExons requires that the start coordinate %u "
		"is less than the end coordinate %u + 1 ", start, end);
	
	return NULL;
    }
    
    strand = ensFeatureGetStrand(feature1);
    
    if(slice1)
	feature = ensFeatureNewS((EnsPAnalysis) NULL,
				 slice1,
				 start,
				 end,
				 strand);
    
    if(seqname1)
	feature = ensFeatureNewN((EnsPAnalysis) NULL,
				 seqname1,
				 start,
				 end,
				 strand);
    
    if(feature)
    {
	AJNEW0(intron);
	
	intron->Feature = feature;
        
	intron->PreviousExon = ensExonNewRef(exon1);
	
	intron->NextExon = ensExonNewRef(exon2);
	
	intron->Use = 1;	
    }
    else
	ajDebug("ensIntronNewExons could not create an Ensembl Feature.\n");
    
    return intron;
}
Example #3
0
static ajint silent_restr_read(AjPList *relist,const AjPStr enzymes)
{
    EmbPPatRestrict rptr = NULL;
    AjPFile fin = NULL;

    AjPStr refilename = NULL;
    register ajint RStotal = 0;
    PRinfo rinfo = NULL;
    AjBool isall = ajFalse;
    ajint ne = 0;
    ajint i;
    AjPStr *ea = NULL;

    refilename = ajStrNewC("REBASE/embossre.enz");
    rptr       = embPatRestrictNew();
    *relist    = ajListNew();

    fin = ajDatafileNewInNameS(refilename);
    if(!fin)
	ajFatal("Aborting...restriction file '%S' not found", refilename);

    /* Parse the user-selected enzyme list */
    if(!enzymes)
	isall = ajTrue;
    else
    {
	ne = ajArrCommaList(enzymes,&ea);
        for(i=0;i<ne;++i)
	    ajStrRemoveWhite(&ea[i]);

        if(ajStrMatchCaseC(ea[0],"all"))
            isall = ajTrue;
        else
            isall = ajFalse;
    }

    while(!ajFileIsEof(fin))
    {
        if(!embPatRestrictReadEntry(rptr,fin))
	    continue;

     	if(!isall)
	{
		for(i=0;i<ne;++i)
		if(ajStrMatchCaseS(ea[i],rptr->cod))
			break;
	    	if(i==ne)
			continue;
        }

        AJNEW(rinfo);
        /* reading in RE info into rinfo from EmbPPatRestrict structure */
        rinfo->code  = ajStrNewC(ajStrGetPtr(rptr->cod));
	rinfo->site  = ajStrNewC(ajStrGetPtr(rptr->pat));
        rinfo->ncuts = rptr->ncuts;
        rinfo->cut1  = rptr->cut1;
        rinfo->cut2  = rptr->cut2;
        rinfo->cut3  = rptr->cut3;
        rinfo->cut4  = rptr->cut4;
	ajListPush(*relist,(void *)rinfo);
	RStotal++;
    }

    for(i=0;i<ne;++i)
	ajStrDel(&ea[i]);
    AJFREE(ea);

    embPatRestrictDel(&rptr);
    ajFileClose(&fin);
    ajStrDel(&refilename);

    return RStotal;
}
Example #4
0
int main(int argc, char **argv)
{
    /*         
    ** All pointers set to NULL for safety. 
    ** Variables names and initialisation values aligned for clarity.
    */

    AjBool    boo   = ajFalse;
    ajint     n1    = 0;
    ajint     n2    = 0;
    ajlong    l1    = 0;     /* long int */
    float     f1    = 0.0;
    double    d1    = 0.0;   /* there is no long double */
    size_t    size  = 100;   /* Reserved memory size.  Could be any value you know in advance. */


    embInit("demostringnew", argc, argv);
    
    demostringnew_msg("/* Starting string values */");
    

    /* Functions with the prefix ajStr are for manipulating EMBOSS strings.
       Functions with the prefix ajChar are for manipulating C-type (char*) string 
       See filesection and datasection sections in ajstr.c */


    /*
    ** String constructor functions 
    ** See "@section constructors" in ajstr.c
    */

    /* Construct a new string with no starting value or reserved size.
       There is no equivlent function for C-type (char*) strings */
    str0  = ajStrNew ();

    /* Construct a new string with a reserved size but no starting value */
    txt1 = ajCharNewRes(size);  
    str1 = ajStrNewRes (size);    

    /* Construct a new C-type (char*) string with a starting value ... */
    txt2 = ajCharNewC ("Starting value");   /* ... copied from a C-type (char*) string */
    str2 = ajStrNewC  (txt2);                /* ... copied from a C-type (char*) string */
    txt3 = ajCharNewS (str2);                /* ... copied from a string */
    str3 = ajStrNewS  (str2);                /* ... copied from a string */

    /* Construct a new string with a reserved size and starting value ... */
    txt4 = ajCharNewResC("Starting value, reserved size", size);  /* ... copied from a C-type (char*) string)*/
    str4 = ajStrNewResC (txt4, size);                              /* ... copied from a C-type (char*) string */
    /* or str4 = ajStrNewResLenC(txt4, size, strlen(txt4)); to specify string length */
    txt5 = ajCharNewResS(str4, size);                              /* ... copied from a string */
    str5 = ajStrNewResS (str4, size);                              /* ... copied from a string */

    demostringnew_msg("/* After string constructor functions */");    





    /*
    ** String destructor functions 
    ** See "@section destructors" in ajstr.c) 
    */
    
    /* Destruct a string */
    ajCharDel(&txt1);
    ajCharDel(&txt2);
    ajCharDel(&txt3);
    ajCharDel(&txt4);
    ajCharDel(&txt5);
    ajStrDel (&str0);
    ajStrDel (&str1);
    ajStrDel (&str3);
    ajStrDel (&str5);

    /* str2 & str4 still in memory */
    demostringnew_msg("/* After string destructor functions */");    





    /*
    ** String (de)referencing functions 
    ** See "@section destructors" in ajstr.c)
    */

    str0 = ajStrNewRef(str2);
    /* or ajStrAssignRef(&str0, str2); */
    demostringnew_msg("/* After string reference */");    

    ajStrDelStatic(&str0);
    demostringnew_msg("/* After string dereference */");    





    /*
    ** String assignment functions 
    ** See "@section assignment" in ajstr.c)
    */

    /* Still only str2 & str4 in memory */

    /* Assign a string value using ... */
    ajStrAssignC(&str1, "Assigned value");     /* ... a C-type (char*) string */
    /*    or ajStrAssignLenC(&str1, "Assigned value", strlen("Assigned value")); to specify string length. */
    ajStrAssignS(&str3, str1);                 /* ... a string                */
    ajStrAssignK(&str5, 'A');                  /* ... a character             */
    demostringnew_msg("/* After string assignment 1 */");    

    ajStrAssignSubC(&str1, "Assigned value", 0, 11);
    ajStrAssignSubS(&str3, str1, 0, 9);
    demostringnew_msg("/* After string assignment 2 */");    

    /* The assignment functions allocate memory if necessary so str1, str3 and str5 will be created for you.  It's bad practice to use this mechanism however because it's not obvious the string has been allocated (and needs freeing).  Much cleaner to call the construct (ajStrNew) explicitly. */



    /* Assign a string with a reserved size and value using ... */
    ajStrAssignResC(&str1, size, "Assigned value, reserved size");  /* ... a C-type (char*) string */
    ajStrAssignResS(&str3, size, str1);                             /* ... a string                */
    demostringnew_msg("/* After string assignment 3 */");    



    /* Assign a string value only if the string is empty using ... */
    str0 = ajStrNew();
    ajStrAssignEmptyC(&str0, "New value if string was empty");    /* ... a C-type (char*) string */ 
    ajStrAssignEmptyS(&str1, str0);                               /* ... a string                */
    demostringnew_msg("/* After string assignment 4 */");    

    /* Now str0-5 in memory.  The above code is for illustrative purposes: it's much cleaner to put all the constructors / destructors at the top / bottom of the code where possible. */


    /* Assign all strings intuitive values */
    txt0 = ajCharNewResC("TEXT 0", 100);   
    txt1 = ajCharNewResC("TEXT 1", 100);   
    txt2 = ajCharNewResC("Text 2", 100);   
    txt3 = ajCharNewResC("Text 3", 100);   
    txt4 = ajCharNewResC("Text 4", 100);   
    txt5 = ajCharNewResC("Text 5", 100);
    ajStrAssignC(&str0, "STRING 0");   
    ajStrAssignC(&str1, "STRING 1");   
    ajStrAssignC(&str2, "String 2");   
    ajStrAssignC(&str3, "String 3");   
    ajStrAssignC(&str4, "String 4 WITHSOMETEXTINABLOCK");   
    ajStrAssignC(&str5, "String 5 WITHSOMETEXTINABLOCK");   
    demostringnew_msg("/* After string assignment 5 */");    





    /*
    ** String formatting functions 
    ** See "@section formatting" in ajstr.c
    */
    ajCharFmtLower(txt0);
    ajCharFmtLower(txt1);
    ajStrFmtLower(&str0);
    ajStrFmtLowerSub(&str1, 0, 2);

    ajCharFmtUpper(txt2);
    ajCharFmtUpper(txt3);
    ajStrFmtUpper(&str2);
    ajStrFmtUpperSub(&str3, 0, 2);
    demostringnew_msg("/* After string formatting 1 */");    


    ajStrFmtTitle(&str0);
    ajStrFmtQuote(&str1);
    ajStrFmtBlock(&str4, 3);
    demostringnew_msg("/* After string formatting 2 */");    


    /* See also ajStrFmtWrap, ajStrFmtWrapLeft
       ... these need checking. */





    /*
    ** String conversion functions 
    ** See "@section datatype to string conversion" in ajstr.c
    */
    n1 = n2 = l1 = 1;
    f1 = d1 = 0.5;
    ajStrFromBool( &str0, boo);
    ajStrFromInt(&str1, n1);
    ajStrFromLong(&str2, l1);
    ajStrFromFloat(&str3, f1, 5);
    ajStrFromDouble(&str4, d1, 5);
    ajStrFromDoubleExp(&str5, d1, 5);
    demostringnew_msg("/* After datatype to string conversion */");    


    /*
    ** String conversion functions 
    ** See "@section string to datatype conversion" in ajstr.c
    */
    ajStrToBool(str0, &boo);
    ajStrToInt(str1, &n1);
    ajStrToLong(str2, &l1);
    ajStrToDouble(str4, &d1);
    ajUser("/* After string to datatype conversion */\n"
	   "boo (from str0): %B\nn1 (from str1): %d\nl1 (from str2): %d", 
	   boo, n1, l1);
    ajFmtPrint("f1 (from str3): %f\nd1 (from str4): %f\n", f1, d1);
    /* Check ajUser ... doesn't support %f */
    /* See also  ajStrToHex */





    /* Assign all strings new values */
    strcpy(txt0, "Text String");
    strcpy(txt1, "TEXT STRING");
    strcpy(txt2, "Text*");
    strcpy(txt3, "Text");
    strcpy(txt4, "Text String 4");
    strcpy(txt5, "Text String 5");

    ajStrAssignC(&str0, "String");   
    ajStrAssignC(&str1, "STRING");   
    ajStrAssignC(&str2, "String*");   
    ajStrAssignC(&str3, "*String");   
    ajStrAssignC(&str4, "String 4");   
    ajStrAssignC(&str5, "String 5");   
    demostringnew_msg("/* After resetting strings */");    





    /*
    ** String comparison functions 
    ** See "@section comparison" in ajstr.c
    */
    ajUserDumpC("/* String comparison functions */");
    boo = ajCharMatchC(txt0, txt1);
    ajUser("ajCharMatchC(txt0 txt1); == %B", boo);
    boo = ajCharMatchCaseC(txt0, txt1);
    ajUser("ajCharMatchCaseC(txt0 txt1); == %B", boo);
    boo = ajCharMatchC(txt0, txt2);
    ajUser("ajCharMatchC(txt0,txt2); == %B", boo);
    boo = ajCharMatchWildC(txt0, txt2);
    ajUser("ajCharMatchWildC(txt0,txt2); == %B", boo);
    boo = ajCharMatchWildS(txt0, str2);
    ajUser("ajCharMatchWildS(txt0,str2); == %B", boo);
    /* See also ajCharMatchWildNextC, ajCharMatchWildWordC
       ... these need checking & documentation updated. */

    boo = ajCharPrefixC(txt0, txt3);
    ajUser("ajCharPrefixC(txt0, txt3); == %B", boo);
    boo = ajCharPrefixS(txt0, str0);
    ajUser("ajCharPrefixS(txt0, str0); == %B", boo);
    boo = ajCharPrefixCaseC(txt5, txt1);
    ajUser("ajCharPrefixCaseC(txt5, txt1); == %B", boo);
    boo = ajCharPrefixCaseC(txt1, txt5);
    ajUser("ajCharPrefixCaseC(txt1, txt5); == %B", boo);
    boo = ajCharPrefixCaseS(txt0, str0);
    ajUser("ajCharPrefixCaseS(txt0, str0); == %B", boo);
    boo = ajCharSuffixC(txt0, txt3);
    ajUser("ajCharSuffixC(txt0, txt3); === %B", boo);
    boo = ajCharSuffixS(txt0, str0);
    ajUser("ajCharSuffixS(txt0, str0); == %B", boo);

    /* See also ajCharSuffixCaseC, ajCharSuffixCaseC, ajCharSuffixCaseS, ajCharSuffixCaseS
       ... these need checking. */
    boo =  ajStrMatchC (str0, txt0);
    ajUser("ajStrMatchC (str0, txt0); == %B", boo);
    boo = ajStrMatchS(str0, str1);
    ajUser("ajStrMatchS(str0, str1); == %B", boo);
    boo = ajStrMatchCaseC(str0, txt0);
    ajUser("ajStrMatchCaseC(str0, txt0); == %B", boo);
    boo = ajStrMatchCaseS(str0, str0);
    ajUser("ajStrMatchCaseS(str0, str0); == %B", boo);


    /*
    ajUser("== %B", boo);

    boo = ajStrMatchWildC(str2, const char* text);
     ajStrMatchWildS  (const AjPStr thys, const AjPStr wild);
     ajStrMatchWildWordC (const AjPStr str, const char* text);
     ajStrMatchWildWordS (const AjPStr str, const AjPStr text);
     ajStrPrefixC(const AjPStr str, const char* txt2);
     ajStrPrefixS(const AjPStr str, const AjPStr str2);
     ajStrPrefixCaseC (const AjPStr str, const char* pref);
     ajStrPrefixCaseS (const AjPStr str, const AjPStr pref);
     ajStrSuffixC (const AjPStr thys, const char* suff);
     ajStrSuffixS (const AjPStr thys, const AjPStr suff);
    */





    /**************************************************************************/
    /* String substitution functions (See "@section substitution" in ajstr.c) */
    /**************************************************************************/

    /*
AjBool     ajStrExchangeCC(AjPStr* Pstr, const char* txt, const char* txtnew);
AjBool     ajStrExchangeCS(AjPStr* Pstr, const char* txt,
                           const AjPStr strnew);
AjBool     ajStrExchangeKK(AjPStr* Pstr, char chr, char chrnew);
AjBool     ajStrExchangeSC(AjPStr* Pstr, const AjPStr str,
                           const char* txtnew);
AjBool     ajStrExchangeSS(AjPStr* Pstr, const AjPStr str,
                           const AjPStr strnew);
AjBool     ajStrExchangeSetCC(AjPStr* Pstr, const char* oldc,
                              const char* newc);
AjBool     ajStrExchangeSetSS(AjPStr* Pstr, const AjPStr str,
                            const AjPStr strnew);
AjBool     ajStrRandom(AjPStr *s);
AjBool     ajStrReverse(AjPStr* Pstr);
    */


    embExit();
    return 0;
}
static void restover_printHits(const AjPSeq seq, const AjPStr seqcmp,
			       AjPFile outf,
			       AjPList l, const AjPStr name, ajint hits,
			       ajint begin, ajint end,
			       ajint mincut, ajint maxcut, AjBool plasmid,
			       ajint sitelen,
			       AjBool limit, const AjPTable table,
			       AjBool alpha, AjBool frags,
			       AjBool html)
{
    EmbPMatMatch m = NULL;
    AjPStr ps = NULL;
    ajint *fa = NULL;
    ajint *fx = NULL;
    ajint fc = 0;
    ajint fn = 0;
    ajint fb = 0;
    ajint last = 0;
    AjPStr overhead = NULL;

    const AjPStr value = NULL;

    ajint i;
    ajint c = 0;

    ajint hang1;
    ajint hang2;


    ps = ajStrNew();
    fn = 0;

    if(html)
	ajFmtPrintF(outf,"<BR>");
    ajFmtPrintF(outf,"# Restrict of %S from %d to %d\n",name,begin,end);

    if(html)
	ajFmtPrintF(outf,"<BR>");
    ajFmtPrintF(outf,"#\n");

    if(html)
	ajFmtPrintF(outf,"<BR>");
    ajFmtPrintF(outf,"# Minimum cuts per enzyme: %d\n",mincut);

    if(html)
	ajFmtPrintF(outf,"<BR>");
    ajFmtPrintF(outf,"# Maximum cuts per enzyme: %d\n",maxcut);

    if(html)
	ajFmtPrintF(outf,"<BR>");
    ajFmtPrintF(outf,"# Minimum length of recognition site: %d\n",
		sitelen);
    if(html)
	ajFmtPrintF(outf,"<BR>");

    hits = embPatRestrictRestrict(l,hits,!limit,alpha);

    if(frags)
    {
	fa = AJALLOC(hits*2*sizeof(ajint));
	fx = AJALLOC(hits*2*sizeof(ajint));
    }


    ajFmtPrintF(outf,"# Number of hits with any overlap: %d\n",hits);

    if(html)
	ajFmtPrintF(outf,"<BR>");

    if(html)
	ajFmtPrintF(outf,"</p><table  border cellpadding=4 "
		    "bgcolor=\"#FFFFF0\">\n");
    if(html)
	ajFmtPrintF(outf,
		    "<th>Base Number</th><th>Enzyme</th><th>Site</th>"
		    "<th>5'</th><th>3'</th><th>[5'</th><th>3']</th>\n");
    else
	ajFmtPrintF(outf,"# Base Number\tEnzyme\t\tSite\t\t5'\t3'\t"
		    "[5'\t3']\n");

    for(i=0;i<hits;++i)
    {
	ajListPop(l,(void **)&m);
	ajDebug("hit %d start:%d cut1:%d cut2:%d\n",
		i, m->start, m->cut1, m->cut2);

	hang1 = (ajint)m->cut1 - (ajint)m->start;
	hang2 = (ajint)m->cut2 - (ajint)m->start;

	if(!plasmid && (hang1>100 || hang2>100))
	{
	    embMatMatchDel(&m);
	    continue;
	}

	if(limit)
	{
	    value=ajTableFetchS(table,m->cod);
	    if(value)
		ajStrAssignS(&m->cod,value);
	}

	if(m->cut2 >= m->cut1)
	    ajStrAssignSubS(&overhead, ajSeqGetSeqS( seq), m->cut1, m->cut2-1);
	else
	{
	    ajStrAssignSubS(&overhead, ajSeqGetSeqS( seq), m->cut2, m->cut1-1);
	    ajStrReverse(&overhead);
	}

	ajDebug("overhead:%S seqcmp:%S\n", overhead, seqcmp);

	/* Print out only those who have the same overhang. */
	if(ajStrMatchCaseS(overhead, seqcmp))
	{
	    if(html)
	    {
		ajFmtPrintF(outf,
			    "<tr><td>%-d</td><td>%-16s</td><td>%-16s"
			    "</td><td>%d</td><td>%d</td></tr>\n",
			    m->start,ajStrGetPtr(m->cod),ajStrGetPtr(m->pat),
			    m->cut1,m->cut2);
	    }
	    else
		ajFmtPrintF(outf,"\t%-d\t%-16s%-16s%d\t%d\t\n",
			    m->start,ajStrGetPtr(m->cod),ajStrGetPtr(m->pat),
			    m->cut1,m->cut2);
	}

	if(frags)
	    fa[fn++] = m->cut1;

	if(m->cut3 || m->cut4)
	{
	    if(m->cut4 >= m->cut3)
		ajStrAssignSubS(&overhead, ajSeqGetSeqS( seq),
				m->cut3, m->cut4-1);
	    else
	    {
		ajStrAssignSubS(&overhead, ajSeqGetSeqS( seq),
				m->cut4, m->cut3-1);
		ajStrReverse(&overhead);
	    }

	    if(ajStrMatchCaseS(overhead, seqcmp))
	    {
		if(html)
		    ajFmtPrintF(outf,
				"<tr><td>%-d</td><td>%-16s</td><td>%-16s"
				"</td><td></td><td></td><td>%d</td><td>%d"
				"</td></tr>\n",
				m->start,ajStrGetPtr(m->cod),
				ajStrGetPtr(m->pat),
				m->cut1,m->cut2);
		else
		    ajFmtPrintF(outf,"\t%-d\t%-16s%-16s\t\t%d\t%d\t\n",
				m->start,ajStrGetPtr(m->cod),
				ajStrGetPtr(m->pat),
				m->cut1,m->cut2);
	    }
	}

	/* I am not sure what fragments are doing so I left it in ...*/
	/* used in the report tail in restrict - restover does much the same */
	if(m->cut3 || m->cut4)
	{
	    if(frags)
		fa[fn++] = m->cut3;
	    /*	       ajFmtPrintF(*outf,"%d\t%d",m->cut3,m->cut4);*/
	}
	ajStrDel(&overhead);

	embMatMatchDel(&m);
    }



    if(frags)
    {
	ajSortIntInc(fa,fn);
	ajFmtPrintF(outf,"\n\nFragment lengths:\n");
	if(!fn || (fn==1 && plasmid))
	    ajFmtPrintF(outf,"    %d\n",end-begin+1);
	else
	{
	    last = -1;
	    fb = 0;
	    for(i=0;i<fn;++i)
	    {
		if((c=fa[i])!=last)
		    fa[fb++]=c;
		last = c;
	    }
	    fn = fb;
	    /* Calc lengths */

	    for(i=0;i<fn-1;++i)
		fx[fc++] = fa[i+1]-fa[i];
	    if(!plasmid)
	    {
		fx[fc++] = fa[0]-begin+1;
		fx[fc++] = end-fa[fn-1];
	    }
	    else
		fx[fc++] = (fa[0]-begin+1)+(end-fa[fn-1]);

	    ajSortIntDec(fx,fc);
	    for(i=0;i<fc;++i)
		ajFmtPrintF(outf,"    %d\n",fx[i]);
	}
	AJFREE(fa);
	AJFREE(fx);
    }


    ajStrDel(&ps);

    if(html)
	ajFmtPrintF(outf,"</table>\n");

    return;
}