DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T u

⟦cd007283f⟧ TextFile

    Length: 18290 (0x4772)
    Types: TextFile
    Names: »ufn_parse.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« 
        └─⟦e5a54fb17⟧ 
            └─⟦this⟧ »pp-5.0/Chans/dirlist/ufn_parse.c« 

TextFile

/* ufn_parse.c - user-friendly name resolution */

# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/dirlist/RCS/ufn_parse.c,v 5.0 90/09/20 15:46:23 pp Exp Locker: pp $";
# endif

/*
 * $Header: /cs/research/pp/hubris/pp-beta/Chans/dirlist/RCS/ufn_parse.c,v 5.0 90/09/20 15:46:23 pp Exp Locker: pp $
 *
 * $Log:	ufn_parse.c,v $
 * Revision 5.0  90/09/20  15:46:23  pp
 * rcsforce : 5.0 public release
 * 
 */



/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


#include "ufn.h"
#include <isode/tailor.h>
#include <isode/quipu/list.h>
#include <isode/quipu/ds_search.h>
#include <isode/quipu/connection.h>	/* ds_search uses di_block - include this for lint !!! */
#include <isode/quipu/dua.h>

char ufn_notify = FALSE;
extern char PY_pepy[];
#define NOTIFY(x) if (ufn_notify) (void) printf x, (void) putchar('\n'); else ;

AttributeType at_OrgUnit;
AttributeType at_Organisation;
AttributeType at_Locality;
AttributeType at_CountryName;
AttributeType at_FriendlyCountryName;
AttributeType at_CommonName;
AttributeType at_Surname;
AttributeType at_Userid;

AttributeType at_ObjectClass;

Attr_Sequence ufnas = NULL;

extern LLog * log_dsap;

extern Filter strfilter ();
extern Filter ocfilter ();
extern Filter joinfilter ();

DNS DNS_append (a,b)
DNS a, b;
{	
DNS c;
	if (a == NULLDNS)
		return b;

	for (c=a; c->dns_next != NULLDNS; c=c->dns_next)
		; /* Nothing */

	c->dns_next = b;

	return a;
}

static Attr_Sequence read (base)
DN base;
{
Entry ptr;

	if ((ptr = local_find_entry (base,FALSE)) != NULLENTRY) 
		return (ptr->e_attributes);

	(void) printf ("You need the bug fix to libquipu.a !!!\n");
	return NULLATTR;
}

static char exact_match (dn,s) 
DN dn;
char * s;
{
RDN rdn;
	for (; dn->dn_parent != NULLDN; dn=dn->dn_parent)
		; /* Nothing */

	for (rdn = dn->dn_rdn; rdn != NULLRDN; rdn=rdn->rdn_next) {
		if (sub_string (rdn->rdn_av.av_syntax)
		&& (lexequ((char *)rdn->rdn_av.av_struct,s) == 0))
			return TRUE;
	}
	return FALSE;
}

static char good_match (dn,s) 
DN dn;
char * s;
{
Attr_Sequence as;
AV_Sequence avs;

	for (as = read(dn); as != NULLATTR; as=as->attr_link)
		for (avs=as->attr_value; avs!= NULLAV; avs=avs->avseq_next)
			if (sub_string (avs->avseq_av.av_syntax)
				&& (lexequ((char *)avs->avseq_av.av_struct,s) == 0))
					return TRUE;
	return FALSE;
}

dnSelect (s,dlist,interact,el)
char * s;
DNS *dlist;
DNS (* interact) ();
DNS el;
{
DNS exact = NULLDNS;
DNS good  = NULLDNS;
DNS bad   = NULLDNS;
DNS tmp, next = NULLDNS;

	if ((dlist == (DNS *)NULL) || (*dlist == NULLDNS))
		return 2;

	for (tmp= *dlist; tmp != NULLDNS; tmp=next) {
		next = tmp->dns_next;
		if (exact_match(tmp->dns_dn,s)) {
			tmp->dns_next = exact;
			exact = tmp;
		} else if (good_match(tmp->dns_dn,s)) {
			tmp->dns_next = good;
			good = tmp;
		} else {
			tmp->dns_next = bad;
			bad = tmp;
		}
	}


	if (exact) {
		NOTIFY (("Found exact match(es) for '%s'",s));
		*dlist = exact;
		dn_seq_free (good);
		dn_seq_free (bad);
		return TRUE;
	}

	if (good) {
		NOTIFY (("Found good match(es) for '%s'",s));
		*dlist = good;
		dn_seq_free (bad);
		return TRUE;
	}

	good = (*interact)(bad,el->dns_dn,s);
	*dlist = good;
	if (good != NULLDNS)
		return TRUE;
	else
		return 2;	/* back track allowed ! */

}

ufn_search (base, subtree, filt, res, s, interact, el)
DN base;
char subtree;
Filter filt;
DNS * res;
char * s;
DNS (* interact) ();
DNS el;
{
struct ds_search_arg search_arg;
static struct ds_search_result result;
struct DSError err;
static CommonArgs ca = default_common_args;
EntryInfo * ptr;
DNS newdns, r = NULLDNS;

	search_arg.sra_baseobject = base;
	search_arg.sra_filter = filt;
	if (subtree)
		search_arg.sra_subset = SRA_WHOLESUBTREE;
	else	
		search_arg.sra_subset = SRA_ONELEVEL;
	search_arg.sra_searchaliases = TRUE;
	search_arg.sra_common = ca; /* struct copy */
	search_arg.sra_eis.eis_infotypes = TRUE;
	search_arg.sra_eis.eis_allattributes = FALSE;
	search_arg.sra_eis.eis_select = ufnas;

#ifdef	DEBUG
	if (ufn_notify == 2)
	    print_search (base, subtree, filt);
#endif
	if (ds_search (&search_arg, &err, &result) != DS_OK) {
		log_ds_error (&err);
		NOTIFY (("DAP Search returned an error"))
		ds_error_free (&err);
		filter_free (filt);
		return FALSE;
	}

	filter_free (filt);
	correlate_search_results (&result);

	if ( (result.CSR_limitproblem != LSR_NOLIMITPROBLEM) || (result.CSR_cr != NULLCONTINUATIONREF)) {
		if ( ! result.CSR_entries) {
			NOTIFY (("Search returned partial results"))
			return FALSE;
		} 
		NOTIFY (("Continuing with partial results !"));
	}

	for (ptr = result.CSR_entries; ptr != NULLENTRYINFO; ptr=ptr->ent_next) {
		cache_entry (ptr,FALSE,TRUE);
		newdns = dn_seq_alloc();
		newdns->dns_next = r;
		newdns->dns_dn = dn_cpy (ptr->ent_dn);
		r = newdns;
	}

	*res = r;

	return dnSelect (s,res,interact,el);
}

static rootSearch (s,interact,el,result)
char * s;
DNS (* interact) ();
DNS el;
DNS * result;
{
Filter filt, filta, filtb, filtc, filtd, filte, filtf;

	if (strlen (s) == 2) {

		filta = strfilter (at_CountryName,s,FILTERITEM_EQUALITY);
		filtb = strfilter (at_FriendlyCountryName,s,FILTERITEM_EQUALITY);
		filtc = strfilter (at_Organisation,s,FILTERITEM_EQUALITY);

		filtb->flt_next = filta;
		filtc->flt_next = filtb;

		filt = joinfilter (filtc, FILTER_OR);

		return ufn_search (NULLDN,FALSE,filt,result,s,interact,el);

	} else {

		filta = strfilter (at_FriendlyCountryName,s,FILTERITEM_SUBSTRINGS);
		filtb = strfilter (at_FriendlyCountryName,s,FILTERITEM_APPROX);
		filtc = strfilter (at_Organisation,s,FILTERITEM_SUBSTRINGS);
		filtd = strfilter (at_Organisation,s,FILTERITEM_APPROX);
		filte = strfilter (at_Locality,s,FILTERITEM_SUBSTRINGS);
		filtf = strfilter (at_Locality,s,FILTERITEM_APPROX);

		filtb->flt_next = filta;
		filtc->flt_next = filtb;
		filtd->flt_next = filtc;
		filte->flt_next = filtd;
		filtf->flt_next = filte;

		filt = joinfilter (filtf, FILTER_OR);

		return ufn_search (NULLDN,FALSE,filt,result,s,interact,el);
	}
}

static char present (d,t)
DN d;
AttributeType t;
{
	for (; d != NULLDN; d=d->dn_parent)
		if (AttrT_cmp (&(d->dn_rdn->rdn_at),t) == 0)
			return TRUE;

	return FALSE;	/* More work ... */
}

static intSearch (base,s,interact,el,result)
DN base;
char * s;
DNS (* interact) ();
DNS el;
DNS * result;
{
Filter filt, filta, filtb, filtc, filtd, filte, filtf, filtg, filth;

	if ( present (base,at_OrgUnit) ) {

		filta = strfilter (at_OrgUnit,s,FILTERITEM_APPROX);
		filtb = strfilter (at_OrgUnit,s,FILTERITEM_SUBSTRINGS);

		filtb->flt_next = filta;

		filt = joinfilter (filtb, FILTER_OR);

		if ((filte = ocfilter ("OrganizationalUnit")) == NULLFILTER)
			return FALSE;

		filte->flt_next = filt;

		filtf = joinfilter (filte, FILTER_AND);

		return ufn_search (base,FALSE,filtf,result,s,interact,el);

	} else if ( present (base,at_Organisation) ) {

		filta = strfilter (at_OrgUnit,s,FILTERITEM_APPROX);
		filtb = strfilter (at_OrgUnit,s,FILTERITEM_SUBSTRINGS);
		filtc = strfilter (at_Locality,s,FILTERITEM_APPROX);
		filtd = strfilter (at_Locality,s,FILTERITEM_SUBSTRINGS);

		filtb->flt_next = filta;
		filtc->flt_next = filtb;
		filtd->flt_next = filtc;

		filt = joinfilter (filtd, FILTER_OR);

		if ((filte = ocfilter ("OrganizationalUnit")) == NULLFILTER)
			return FALSE;
		if ((filth = ocfilter ("Locality")) == NULLFILTER)
			return FALSE;

		filth->flt_next = filte;

		filtg = joinfilter (filth, FILTER_OR);
		filtg->flt_next = filt;
		filtf = joinfilter (filtg, FILTER_AND);

		return ufn_search (base,FALSE,filtf,result,s,interact,el);

	} else if ( present (base,at_Locality) ) {

		filta = strfilter (at_Organisation,s,FILTERITEM_APPROX);
		filtb = strfilter (at_Organisation,s,FILTERITEM_SUBSTRINGS);

		filtb->flt_next = filta;

		filt = joinfilter (filtb, FILTER_OR);

		if ((filte = ocfilter ("Organization")) == NULLFILTER)
			return FALSE;

		filte->flt_next = filt;

		filtf = joinfilter (filte, FILTER_AND);

		return ufn_search (base,FALSE,filtf,result,s,interact,el);
	} else {
		filta = strfilter (at_Organisation,s,FILTERITEM_APPROX);
		filtb = strfilter (at_Organisation,s,FILTERITEM_SUBSTRINGS);
		filtc = strfilter (at_Locality,s,FILTERITEM_APPROX);
		filtd = strfilter (at_Locality,s,FILTERITEM_SUBSTRINGS);

		filtb->flt_next = filta;
		filtc->flt_next = filtb;
		filtd->flt_next = filtc;

		filt = joinfilter (filtd, FILTER_OR);

		if ((filte = ocfilter ("Organization")) == NULLFILTER)
			return FALSE;
		if ((filth = ocfilter ("Locality")) == NULLFILTER)
			return FALSE;

		filth->flt_next = filte;

		filtg = joinfilter (filth, FILTER_OR);
		filtg->flt_next = filt;
		filtf = joinfilter (filtg, FILTER_AND);

		return ufn_search (base,FALSE,filtf,result,s,interact,el);
	}
}

static leafSearch (base,s,subtree,interact,el,result)
DN base;
char * s;
char subtree;
DNS (* interact) ();
DNS el;
DNS * result;
{
Filter filt, filta, filtb, filtc, filtd, filte, filtf;

	filta = strfilter (at_CommonName,s,FILTERITEM_APPROX);
	filtb = strfilter (at_CommonName,s,FILTERITEM_SUBSTRINGS);
	filtc = strfilter (at_Surname,s,FILTERITEM_APPROX);
	filtd = strfilter (at_Surname,s,FILTERITEM_SUBSTRINGS);
	filte = strfilter (at_Userid,s,FILTERITEM_APPROX);
	filtf = strfilter (at_Userid,s,FILTERITEM_SUBSTRINGS);

	filtb->flt_next = filta;
	filtc->flt_next = filtb;
	filtd->flt_next = filtc;
	filte->flt_next = filtd;
	filtf->flt_next = filte;

	filt = joinfilter (filtf, FILTER_OR);

	return ufn_search (base,subtree,filt,result,s,interact,el);
}

static keyedSearch (base,t,v,interact,el,result)
DN base;
char * t, *v; 
DNS (* interact) ();
DNS el;
DNS * result;
{
Filter filt, filta, filtb;
AttributeType at;

	if ((at = AttrT_new (t)) == NULLAttrT) {
		NOTIFY (("Invalid Key !"));
		return FALSE;
	}
	if ( ! sub_string (at->at_table->oa_syntax)) {
		NOTIFY (("String types only !"));
		return FALSE;
	}

	filta = strfilter (at,v,FILTERITEM_SUBSTRINGS);
	filtb = strfilter (at,v,FILTERITEM_APPROX);

	filtb->flt_next = filta;

	filt = joinfilter (filtb, FILTER_OR);

	if (base && base->dn_parent)
		return ufn_search (base,TRUE,filt,result,v,interact,el);
	else
		return ufn_search (base,FALSE,filt,result,v,interact,el);
}


static purportedMatch(base,c,v,interact,el,result)
DN base;
int c;
char ** v;
DNS (* interact) ();
DNS el;
DNS * result;
{
char * s = v[c-1];
DNS root, x, new = NULLDNS;
char * ptr;
int matches;

	if (c == 1) {

		if ((ptr = index (s,'=')) != NULLCP) {
			*ptr++ = 0;
			matches = keyedSearch (base,SkipSpace(s),SkipSpace(ptr),interact,el,result);
			*(--ptr) = '=';
			return matches;
		} else if (base == NULLDN) {
			matches = rootSearch(s,interact,el,result);
			if (*result != NULLDNS)
				return matches;
			else if (matches == TRUE)
				return TRUE;
			else
				return leafSearch (base,s,FALSE,interact,el,result);
		} else if (base->dn_parent == NULLDN) {
			/* length == 1 */
			matches = intSearch (base,s,interact,el,result);
			if (*result != NULLDNS)
				return matches;
			else if (matches == TRUE)
				return TRUE;
			else
				return leafSearch (base,s,FALSE,interact,el,result);
		} else {
			matches = leafSearch (base,s,TRUE,interact,el,result);
			if (*result != NULLDNS)
				return matches;
			else if (matches == TRUE)
				return TRUE;
			else
				return intSearch (base,s,interact,el,result);
		}
	}

	if ((ptr = index (s,'=')) != NULLCP) {
		*ptr++ = 0;
		if ( ! (matches = keyedSearch (base,SkipSpace(s),SkipSpace(ptr),interact,el,&root))) {
			*(--ptr) = '=';
			return FALSE;
		}
		*(--ptr) = '=';
	} else if (base == NULLDN) {
		if ( ! (matches = rootSearch (s,interact,el,&root)))
			return FALSE;
	} else {
		if ( ! (matches = intSearch (base,s,interact,el,&root)))
			return FALSE;
	}

	for (x = root; x != NULLDNS; x = x->dns_next) {
		if (purportedMatch (x->dns_dn, c-1, v,interact,el,&new)) {
			if (new != NULLDNS)
				*result = DNS_append (*result,new);
		} else
			return FALSE;
	}

	return matches;
}

static envMatch (c,v,el,interact,result)
int c;
char ** v;
DNS el;
DNS (* interact) ();
DNS * result;
{
int res;

	if (el == NULLDNS)
		return TRUE;

	if ( ! ( res = purportedMatch(el->dns_dn,c,v,interact,el,result)))
		return FALSE;
	if (*result != NULLDNS)	
		return res;
	if (res == TRUE)
		return TRUE;		

	return envMatch(c,v,el->dns_next,interact,result);

}

static	friendlyMatch_aux (c,v,el,interact,result)
int c;
char ** v;
envlist el;
DNS (* interact) ();
DNS * result;
{
	if (el == NULLEL)
		return TRUE;

	if ( ( c <= el->Upper) && (c >= el->Lower) ) 
		return envMatch (c,v,el->Dns,interact,result);

	return (friendlyMatch_aux (c,v,el->Next,interact,result));

}

envlist read_envlist()
{
char * home, *p, *ptr;
char ufnrc [LINESIZE];
char * def;
char buffer [LINESIZE];
envlist env, top = NULLEL, trail = NULLEL;
DNS dtail = NULLDNS;
FILE * file;
DN dn;
int i = 0;
extern char * TidyString ();

	if (home = getenv ("UFNRC"))
		(void) strcpy (ufnrc, home);
	else 
		if (home = getenv ("HOME"))
			(void) sprintf (ufnrc, "%s/.ufnrc", home);
		else
			(void) strcpy (ufnrc, "./.ufnrc");

	if ((file = fopen (ufnrc,"r")) == 0) {
		def = isodefile("ufnrc",0);
		if ((file = fopen(def,"r")) == 0) {
			(void) sprintf (PY_pepy,"Can't open '%s' or '%s'",ufnrc,def);
			return NULLEL;
		}
	}

	while (fgets (buffer, LINESIZE, file) != 0) {
		i++;
		p = buffer;
		if (( *p == '#') || (*p == '\0') || (*p == '\n'))
			continue; 	/* ignore comments and blanks */

		if (isspace (*p)) {
			/* part of current environment */
			if (!dtail) {
				(void) sprintf (PY_pepy, "Unexpected blank at start of line %d",i);
				(void) fclose (file);
				return NULLEL;
			}
			p = TidyString(p);
			if (*p == '-')
				dn = NULLDN;
			else if ((dn = str2dn (p)) == NULLDN) {
				(void) sprintf (PY_pepy, "Bad DN in environment file line %d",i);
				(void) fclose (file);
				return NULLEL;
			}
			dtail->dns_next = dn_seq_alloc();
			dtail = dtail->dns_next;
			dtail->dns_next = NULLDNS;
			dtail->dns_dn   = dn;
			continue;
		}

		p = TidyString (p);

		if ((ptr = index (p,':')) == NULLCP) {
			(void) sprintf (PY_pepy, "':' missing in environment file line %d",i);
			(void) fclose (file);
			return NULLEL;
		}

		*ptr++ = 0;
		ptr = SkipSpace (ptr);

		if (*ptr == '-')
			dn = NULLDN;
		else if ((dn = str2dn (ptr)) == NULLDN) {
			(void) sprintf (PY_pepy, "Bad DN in environment file line %d",i);
			(void) fclose (file);
			return NULLEL;
		}

		env = (envlist) smalloc (sizeof (*env));
		dtail = env->Dns = dn_seq_alloc();
		dtail->dns_next = NULLDNS;
		dtail->dns_dn   = dn;
		env->Next = NULLEL;
		if (top == NULLEL)
			top = env;
		else 
			trail->Next = env;
		trail = env;

		if ((ptr = index (p,',')) != NULLCP) {
			*ptr++ = 0;
			ptr = SkipSpace(ptr);
			if (*ptr == '+')
				env->Upper = 32767;	/* ~= infinity */
			else 
				env->Upper = atoi (ptr);	/* how to test error ? */
		} else
			env->Upper = 0;
		
		p = SkipSpace(p);

		env->Lower = atoi (p);		/* how to test error ? */

		if ( ! env->Upper)
			env->Upper = env->Lower;

	}

	(void) fclose (file);

	return top;
}


ufn_match (c,v,interact,result,el)
int c;
char ** v;
DNS (* interact) ();
DNS * result;
envlist el;
{
static int inited = FALSE;

	if ( (!ufnas) && !(inited = ufn_init()))
		return inited;
	
	PY_pepy[0] = NULL;
	if (el == NULLEL) {
		if ((el = read_envlist ()) == NULLEL) {
			(void) sprintf (PY_pepy,"Can't read environment");
			return 0;
		}
	}

	return (friendlyMatch_aux (c,v,el,interact,result));
}

ufn_init ()
{
Attr_Sequence as;
int result = TRUE;

	if (ufnas)
	    return result;

	if ((at_ObjectClass = AttrT_new ("ObjectClass")) == NULLAttrT) {
		result = FALSE;
		LLOG (log_dsap,LLOG_EXCEPTIONS,("ObjectClass attribute unknown"));
	}

	if ((at_OrgUnit	= AttrT_new ("ou")) == NULLAttrT) {
		result = FALSE;
		LLOG (log_dsap,LLOG_EXCEPTIONS,("ou attribute unknown"));
	}
	if ((at_Organisation = AttrT_new ("o")) == NULLAttrT) {
		result = FALSE;
		LLOG (log_dsap,LLOG_EXCEPTIONS,("o attribute unknown"));
	}
	if ((at_Locality = AttrT_new ("l")) == NULLAttrT) {
		result = FALSE;
		LLOG (log_dsap,LLOG_EXCEPTIONS,("l attribute unknown"));
	}
	if ((at_CountryName = AttrT_new ("c")) == NULLAttrT) {
		result = FALSE;
		LLOG (log_dsap,LLOG_EXCEPTIONS,("c attribute unknown"));
	}
	if ((at_FriendlyCountryName = AttrT_new ("FriendlyCountryName")) == NULLAttrT) {
		result = FALSE;
		LLOG (log_dsap,LLOG_EXCEPTIONS,("FriendlyCountryName attribute unknown"));
	}
	if ((at_CommonName = AttrT_new (CN_OID)) == NULLAttrT) {
		result = FALSE;
		LLOG (log_dsap,LLOG_EXCEPTIONS,("cn attribute unknown"));
	}
	if ((at_Surname	= AttrT_new ("sn")) == NULLAttrT) {
		result = FALSE;
		LLOG (log_dsap,LLOG_EXCEPTIONS,("sn attribute unknown"));
	}
	if ((at_Userid = AttrT_new ("uid")) == NULLAttrT) {
		result = FALSE;
		LLOG (log_dsap,LLOG_EXCEPTIONS,("uid attribute unknown"));
	}

	ufnas = as_comp_new (at_OrgUnit,NULLAV,NULLACL_INFO);
	as = as_comp_new (at_Organisation,NULLAV,NULLACL_INFO);
	ufnas = as_merge (ufnas,as);
	as = as_comp_new (at_Locality,NULLAV,NULLACL_INFO);
	ufnas = as_merge (ufnas,as);
	as = as_comp_new (at_CountryName,NULLAV,NULLACL_INFO);
	ufnas = as_merge (ufnas,as);
	as = as_comp_new (at_FriendlyCountryName,NULLAV,NULLACL_INFO);
	ufnas = as_merge (ufnas,as);
	as = as_comp_new (at_CommonName,NULLAV,NULLACL_INFO);
	ufnas = as_merge (ufnas,as);
	as = as_comp_new (at_Surname,NULLAV,NULLACL_INFO);
	ufnas = as_merge (ufnas,as);
	as = as_comp_new (at_Userid,NULLAV,NULLACL_INFO);
	ufnas = as_merge (ufnas,as);

	return result;
}

#ifdef	DEBUG

static	print_search (dn, subtree, fi)
DN	dn;
char	subtree;
Filter	fi;
{
static	PS	nps = NULLPS;

    if (nps == NULLPS) {
	if ((nps = ps_alloc (std_open)) == NULL) {
	    (void) fprintf (stderr, "ps_alloc(std_open): you lose\n");
	    return;
	}
	if (std_setup (nps, stdout) == NOTOK) {
	    (void) fprintf (stderr, "std_setup(stdout): you lose\n");
	    ps_free (nps);
	    nps = NULL;
	    return;
	}
    }
    
    ps_printf (nps, "search starting at @");
    dn_print (nps, dn, EDBOUT);
    ps_printf (nps, "(%s) for ", subtree ? "subtree" : "singlelevel");

    print_filter (nps, fi, 0);

    ps_print (nps, "\n\n");
    (void) ps_flush (nps);
}


#endif