__libc_res_nsearch(res_state statp,
		   const char *name,	/* domain name */
		   int class, int type,	/* class and type of query */
		   u_char *answer,	/* buffer to put answer */
		   int anslen,		/* size of answer */
		   u_char **answerp,
		   u_char **answerp2,
		   int *nanswerp2,
		   int *resplen2,
		   int *answerp2_malloced)
{
	const char *cp, * const *domain;
	HEADER *hp = (HEADER *) answer;
	char tmp[NS_MAXDNAME];
	u_int dots;
	int trailing_dot, ret, saved_herrno;
	int got_nodata = 0, got_servfail = 0, root_on_list = 0;
	int tried_as_is = 0;
	int searched = 0;

	__set_errno (0);
	RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);  /* True if we never query. */

	dots = 0;
	for (cp = name; *cp != '\0'; cp++)
		dots += (*cp == '.');
	trailing_dot = 0;
	if (cp > name && *--cp == '.')
		trailing_dot++;

	/* If there aren't any dots, it could be a user-level alias. */
	if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
		return (__libc_res_nquery(statp, cp, class, type, answer,
					  anslen, answerp, answerp2,
					  nanswerp2, resplen2, answerp2_malloced));

#ifdef DEBUG
	if (statp->options & RES_DEBUG)
		printf("dots=%d, statp->ndots=%d, trailing_dot=%d, name=%s\n",
		       (int)dots,(int)statp->ndots,(int)trailing_dot,name);
#endif

	/*
	 * If there are enough dots in the name, let's just give it a
	 * try 'as is'. The threshold can be set with the "ndots" option.
	 * Also, query 'as is', if there is a trailing dot in the name.
	 */
	saved_herrno = -1;
	if (dots >= statp->ndots || trailing_dot) {
		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
					      answer, anslen, answerp,
					      answerp2, nanswerp2, resplen2,
					      answerp2_malloced);
		if (ret > 0 || trailing_dot
		    /* If the second response is valid then we use that.  */
		    || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
			return (ret);
		saved_herrno = h_errno;
		tried_as_is++;
		if (answerp && *answerp != answer) {
			answer = *answerp;
			anslen = MAXPACKET;
		}
		if (answerp2 && *answerp2_malloced)
		  {
		    free (*answerp2);
		    *answerp2 = NULL;
		    *nanswerp2 = 0;
		    *answerp2_malloced = 0;
		  }
	}

	/*
	 * We do at least one level of search if
	 *	- there is no dot and RES_DEFNAME is set, or
	 *	- there is at least one dot, there is no trailing dot,
	 *	  and RES_DNSRCH is set.
	 */
	if ((!dots && (statp->options & RES_DEFNAMES) != 0) ||
	    (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
		int done = 0;

		for (domain = (const char * const *)statp->dnsrch;
		     *domain && !done;
		     domain++) {
			const char *dname = domain[0];
			searched = 1;

			/* __libc_res_nquerydoman concatenates name
			   with dname with a "." in between.  If we
			   pass it in dname the "." we got from the
			   configured default search path, we'll end
			   up with "name..", which won't resolve.
			   OTOH, passing it "" will result in "name.",
			   which has the intended effect for both
			   possible representations of the root
			   domain.  */
			if (dname[0] == '.')
				dname++;
			if (dname[0] == '\0')
				root_on_list++;

			ret = __libc_res_nquerydomain(statp, name, dname,
						      class, type,
						      answer, anslen, answerp,
						      answerp2, nanswerp2,
						      resplen2, answerp2_malloced);
			if (ret > 0 || (ret == 0 && resplen2 != NULL
					&& *resplen2 > 0))
				return (ret);

			if (answerp && *answerp != answer) {
				answer = *answerp;
				anslen = MAXPACKET;
			}
			if (answerp2 && *answerp2_malloced)
			  {
			    free (*answerp2);
			    *answerp2 = NULL;
			    *nanswerp2 = 0;
			    *answerp2_malloced = 0;
			  }

			/*
			 * If no server present, give up.
			 * If name isn't found in this domain,
			 * keep trying higher domains in the search list
			 * (if that's enabled).
			 * On a NO_DATA error, keep trying, otherwise
			 * a wildcard entry of another type could keep us
			 * from finding this entry higher in the domain.
			 * If we get some other error (negative answer or
			 * server failure), then stop searching up,
			 * but try the input name below in case it's
			 * fully-qualified.
			 */
			if (errno == ECONNREFUSED) {
				RES_SET_H_ERRNO(statp, TRY_AGAIN);
				return (-1);
			}

			switch (statp->res_h_errno) {
			case NO_DATA:
				got_nodata++;
				/* FALLTHROUGH */
			case HOST_NOT_FOUND:
				/* keep trying */
				break;
			case TRY_AGAIN:
				if (hp->rcode == SERVFAIL) {
					/* try next search element, if any */
					got_servfail++;
					break;
				}
				/* FALLTHROUGH */
			default:
				/* anything else implies that we're done */
				done++;
			}

			/* if we got here for some reason other than DNSRCH,
			 * we only wanted one iteration of the loop, so stop.
			 */
			if ((statp->options & RES_DNSRCH) == 0)
				done++;
		}
	}

	/*
	 * If the query has not already been tried as is then try it
	 * unless RES_NOTLDQUERY is set and there were no dots.
	 */
	if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0)
	    && !(tried_as_is || root_on_list)) {
		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
					      answer, anslen, answerp,
					      answerp2, nanswerp2, resplen2,
					      answerp2_malloced);
		if (ret > 0 || (ret == 0 && resplen2 != NULL
				&& *resplen2 > 0))
			return (ret);
	}

	/* if we got here, we didn't satisfy the search.
	 * if we did an initial full query, return that query's H_ERRNO
	 * (note that we wouldn't be here if that query had succeeded).
	 * else if we ever got a nodata, send that back as the reason.
	 * else send back meaningless H_ERRNO, that being the one from
	 * the last DNSRCH we did.
	 */
	if (answerp2 && *answerp2_malloced)
	  {
	    free (*answerp2);
	    *answerp2 = NULL;
	    *nanswerp2 = 0;
	    *answerp2_malloced = 0;
	  }
	if (saved_herrno != -1)
		RES_SET_H_ERRNO(statp, saved_herrno);
	else if (got_nodata)
		RES_SET_H_ERRNO(statp, NO_DATA);
	else if (got_servfail)
		RES_SET_H_ERRNO(statp, TRY_AGAIN);
	return (-1);
}