static Embryo_Cell
_embryo_str_strcut(Embryo_Program *ep, Embryo_Cell *params)
{
   char *s1, *s2;
   int l1;

   /* params[1] = dst */
   /* params[2] = str */
   /* params[3] = n */
   /* params[4] = n2 */
   if (params[0] != (4 * sizeof(Embryo_Cell))) return 0;
   if (params[3] < 0) params[3] = 0;
   if (params[4] < params[3]) params[4] = params[3];
   STRGET(ep, s1, params[2]);
   if (!s1) return 0;
   l1 = strlen(s1);
   if (params[3] >= l1) params[3] = l1;
   if (params[4] >= l1) params[4] = l1;
   if (params[4] == params[3])
     {
	STRSET(ep, params[1], "");
	return 0;
     }
   s2 = alloca(params[4] - params[3] + 1);
   strncpy(s2, s1 + params[3], params[4] - params[3]);
   s2[params[4] - params[3]] = 0;
   STRSET(ep, params[1], s2);
   return 0;
}
static Embryo_Cell
_embryo_str_strcpy(Embryo_Program *ep, Embryo_Cell *params)
{
   char *s1;

   /* params[1] = dst */
   /* params[2] = str */
   if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
   STRGET(ep, s1, params[2]);
   if (!s1) return 0;
   STRSET(ep, params[1], s1);
   return 0;
}
Esempio n. 3
0
File: files.c Progetto: Yomin/remind
static int PopFile(void)
{
    IncludeStruct *i;

    /* Assume we own the file for now */
    RunDisabled &= ~RUN_NOTOWNER;

    if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]);
    if (!IStackPtr) return E_EOF;
    i = &IStack[IStackPtr-1];

    if (i->chain) {
	int oldRunDisabled = RunDisabled;
	if (NextChainedFile(i) == OK) {
	    return OK;
	}
	RunDisabled = oldRunDisabled;
    }

    if (IStackPtr <= 1) {
	return E_EOF;
    }

    IStackPtr--;

    LineNo = i->LineNo;
    IfFlags = i->IfFlags;
    NumIfs = i->NumIfs;
    CLine = i->CLine;
    fp = NULL;
    STRSET(FileName, i->filename);
    if (!i->ownedByMe) {
	RunDisabled |= RUN_NOTOWNER;
    }
    if (!CLine && (i->offset != -1L)) {
	/* We must open the file, then seek to specified position */
	if (strcmp(i->filename, "-")) {
	    fp = fopen(i->filename, "r");
	    if (!fp || !CheckSafety()) return E_CANT_OPEN;
	    if (PurgeMode) OpenPurgeFile(i->filename, "a");
	} else {
	    fp = stdin;
	    if (PurgeMode) PurgeFP = stdout;
	}
	if (fp != stdin)
	    (void) fseek(fp, i->offset, 0);  /* Trust that it works... */
    }
    free((char *) i->filename);
    return OK;
}
static Embryo_Cell
_embryo_str_strprep(Embryo_Program *ep, Embryo_Cell *params)
{
   char *s1, *s2, *s3;

   /* params[1] = dst */
   /* params[2] = str */
   if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
   STRGET(ep, s1, params[1]);
   STRGET(ep, s2, params[2]);
   if ((!s1) || (!s2)) return 0;
   s3 = alloca(strlen(s1) + strlen(s2) + 1);
   if (!s3) return 0;
   strcpy(s3, s2);
   strcat(s3, s1);
   STRSET(ep, params[1], s3);
   return 0;
}
static Embryo_Cell
_embryo_str_strncpy(Embryo_Program *ep, Embryo_Cell *params)
{
   char *s1;
   int l;

   /* params[1] = dst */
   /* params[2] = str */
   /* params[3] = n */
   if (params[0] != (3 * sizeof(Embryo_Cell))) return 0;
   if (params[3] < 0) params[3] = 0;
   STRGET(ep, s1, params[2]);
   if (!s1) return 0;
   l = strlen(s1);
   if (l > params[3]) s1[params[3]] = 0;
   STRSET(ep, params[1], s1);
   return 0;
}
static Embryo_Cell
_embryo_str_strnprep(Embryo_Program *ep, Embryo_Cell *params)
{
   char *s1, *s2, *s3;
   int l1, l2;

   /* params[1] = dst */
   /* params[2] = str */
   /* params[3] = n */
   if (params[0] != (3 * sizeof(Embryo_Cell))) return 0;
   if (params[3] < 0) params[3] = 0;
   STRGET(ep, s1, params[1]);
   STRGET(ep, s2, params[2]);
   if ((!s1) || (!s2)) return 0;
   l1 = strlen(s1);
   l2 = strlen(s2);
   s3 = alloca(l1 + l2 + 1);
   if (!s3) return 0;
   strncpy(s3, s2, params[3]);
   if (params[3] <= l2) s3[params[3]] = 0;
   strcat(s3, s1);
   STRSET(ep, params[1], s3);
   return 0;
}
Esempio n. 7
0
/*
 * v_replace -- [count]r<char>
 *
 * !!!
 * The r command in historic vi was almost beautiful in its badness.  For
 * example, "r<erase>" and "r<word erase>" beeped the terminal and deleted
 * a single character.  "Nr<carriage return>", where N was greater than 1,
 * inserted a single carriage return.  "r<escape>" did cancel the command,
 * but "r<literal><escape>" erased a single character.  To enter a literal
 * <literal> character, it required three <literal> characters after the
 * command.  This may not be right, but at least it's not insane.
 *
 * PUBLIC: int v_replace __P((SCR *, VICMD *));
 */
int
v_replace(SCR *sp, VICMD *vp)
{
	EVENT ev;
	VI_PRIVATE *vip;
	TEXT *tp;
	size_t blen, len;
	u_long cnt;
	int quote, rval;
	CHAR_T *bp;
	CHAR_T *p;

	vip = VIP(sp);

	/*
	 * If the line doesn't exist, or it's empty, replacement isn't
	 * allowed.  It's not hard to implement, but:
	 *
	 *	1: It's historic practice (vi beeped before the replacement
	 *	   character was even entered).
	 *	2: For consistency, this change would require that the more
	 *	   general case, "Nr", when the user is < N characters from
	 *	   the end of the line, also work, which would be a bit odd.
	 *	3: Replacing with a <newline> has somewhat odd semantics.
	 */
	if (db_get(sp, vp->m_start.lno, DBG_FATAL, &p, &len))
		return (1);
	if (len == 0) {
		msgq(sp, M_BERR, "186|No characters to replace");
		return (1);
	}

	/*
	 * Figure out how many characters to be replace.  For no particular
	 * reason (other than that the semantics of replacing the newline
	 * are confusing) only permit the replacement of the characters in
	 * the current line.  I suppose we could append replacement characters
	 * to the line, but I see no compelling reason to do so.  Check this
	 * before we get the character to match historic practice, where Nr
	 * failed immediately if there were less than N characters from the
	 * cursor to the end of the line.
	 */
	cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
	vp->m_stop.lno = vp->m_start.lno;
	vp->m_stop.cno = vp->m_start.cno + cnt - 1;
	if (vp->m_stop.cno > len - 1) {
		v_eol(sp, &vp->m_start);
		return (1);
	}

	/*
	 * If it's not a repeat, reset the current mode and get a replacement
	 * character.
	 */
	quote = 0;
	if (!F_ISSET(vp, VC_ISDOT)) {
		sp->showmode = SM_REPLACE;
		if (vs_refresh(sp, 0))
			return (1);
next:		if (v_event_get(sp, &ev, 0, 0))
			return (1);

		switch (ev.e_event) {
		case E_CHARACTER:
			/*
			 * <literal_next> means escape the next character.
			 * <escape> means they changed their minds.
			 */
			if (!quote) {
				if (ev.e_value == K_VLNEXT) {
					quote = 1;
					goto next;
				}
				if (ev.e_value == K_ESCAPE)
					return (0);
			}
			vip->rlast = ev.e_c;
			vip->rvalue = ev.e_value;
			break;
		case E_ERR:
		case E_EOF:
			F_SET(sp, SC_EXIT_FORCE);
			return (1);
		case E_INTERRUPT:
			/* <interrupt> means they changed their minds. */
			return (0);
		case E_WRESIZE:
			/* <resize> interrupts the input mode. */
			v_emsg(sp, NULL, VIM_WRESIZE);
			return (0);
		case E_REPAINT:
			if (vs_repaint(sp, &ev))
				return (1);
			goto next;
		default:
			v_event_err(sp, &ev);
			return (0);
		}
	}

	/* Copy the line. */
	GET_SPACE_RETW(sp, bp, blen, len);
	MEMMOVE(bp, p, len);
	p = bp;

	/*
	 * Versions of nvi before 1.57 created N new lines when they replaced
	 * N characters with <carriage-return> or <newline> characters.  This
	 * is different from the historic vi, which replaced N characters with
	 * a single new line.  Users complained, so we match historic practice.
	 */
	if ((!quote && vip->rvalue == K_CR) || vip->rvalue == K_NL) {
		/* Set return line. */
		vp->m_stop.lno = vp->m_start.lno + 1;
		vp->m_stop.cno = 0;

		/* The first part of the current line. */
		if (db_set(sp, vp->m_start.lno, p, vp->m_start.cno))
			goto err_ret;

		/*
		 * The rest of the current line.  And, of course, now it gets
		 * tricky.  If there are characters left in the line and if
		 * the autoindent edit option is set, white space after the
		 * replaced character is discarded, autoindent is applied, and
		 * the cursor moves to the last indent character.
		 */
		p += vp->m_start.cno + cnt;
		len -= vp->m_start.cno + cnt;
		if (len != 0 && O_ISSET(sp, O_AUTOINDENT))
			for (; len && isblank(*p); --len, ++p);

		if ((tp = text_init(sp, p, len, len)) == NULL)
			goto err_ret;

		if (len != 0 && O_ISSET(sp, O_AUTOINDENT)) {
			if (v_txt_auto(sp, vp->m_start.lno, NULL, 0, tp))
				goto err_ret;
			vp->m_stop.cno = tp->ai ? tp->ai - 1 : 0;
		} else
			vp->m_stop.cno = 0;

		vp->m_stop.cno = tp->ai ? tp->ai - 1 : 0;
		if (db_append(sp, 1, vp->m_start.lno, tp->lb, tp->len))
err_ret:		rval = 1;
		else {
			text_free(tp);
			rval = 0;
		}
	} else {
		STRSET(bp + vp->m_start.cno, vip->rlast, cnt);
		rval = db_set(sp, vp->m_start.lno, bp, len);
	}
	FREE_SPACEW(sp, bp, blen);

	vp->m_final = vp->m_stop;
	return (rval);
}
Esempio n. 8
0
File: files.c Progetto: Yomin/remind
int OpenFile(char const *fname)
{
    CachedFile *h = CachedFiles;
    int r;

    if (PurgeMode) {
	if (PurgeFP != NULL && PurgeFP != stdout) {
	    fclose(PurgeFP);
	}
	PurgeFP = NULL;
    }

/* Assume we own the file for now */
    RunDisabled &= ~RUN_NOTOWNER;

/* If it's in the cache, get it from there. */

    while (h) {
	if (!strcmp(fname, h->filename)) {
	    if (DebugFlag & DB_TRACE_FILES) {
		fprintf(ErrFp, "Reading `%s': Found in cache\n", fname);
	    }
	    CLine = h->cache;
	    STRSET(FileName, fname);
	    LineNo = 0;
	    if (!h->ownedByMe) {
		RunDisabled |= RUN_NOTOWNER;
	    }
	    if (FileName) return OK; else return E_NO_MEM;
	}
	h = h->next;
    }

/* If it's a dash, then it's stdin */
    if (!strcmp(fname, "-")) {
	fp = stdin;
	if (PurgeMode) {
	    PurgeFP = stdout;
	}
	if (DebugFlag & DB_TRACE_FILES) {
	    fprintf(ErrFp, "Reading `-': Reading stdin\n");
	}
    } else {
	fp = fopen(fname, "r");
	if (DebugFlag & DB_TRACE_FILES) {
	    fprintf(ErrFp, "Reading `%s': Opening file on disk\n", fname);
	}
	if (PurgeMode) {
	    OpenPurgeFile(fname, "w");
	}
    }
    if (!fp || !CheckSafety()) return E_CANT_OPEN;
    CLine = NULL;
    if (ShouldCache) {
	LineNo = 0;
	r = CacheFile(fname);
	if (r == OK) {
	    fp = NULL;
	    CLine = CachedFiles->cache;
	} else {
	    if (strcmp(fname, "-")) {
		fp = fopen(fname, "r");
		if (!fp || !CheckSafety()) return E_CANT_OPEN;
		if (PurgeMode) OpenPurgeFile(fname, "w");
	    } else {
		fp = stdin;
		if (PurgeMode) PurgeFP = stdout;
	    }
	}
    }
    STRSET(FileName, fname);
    LineNo = 0;
    if (FileName) return OK; else return E_NO_MEM;
}
static Embryo_Cell
_embryo_str_snprintf(Embryo_Program *ep, Embryo_Cell *params)
{
   char *s1, *s2;
   int i, o;
   int inesc = 0;
   int insub = 0;
   int p, pnum;

   /* params[1] = buf */
   /* params[2] = bufsize */
   /* params[3] = format_string */
   /* params[4] = first arg ... */
   if (params[0] < (Embryo_Cell)(3 * sizeof(Embryo_Cell))) return 0;
   if (params[2] <= 0) return 0;
   STRGET(ep, s1, params[3]);
   if (!s1) return -1;
   s2 = alloca(params[2] + 1);
   if (!s2) return -1;
   s2[0] = 0;
   pnum = (params[0] / sizeof(Embryo_Cell)) - 3;
   for (p = 0, o = 0, i = 0; (s1[i]) && (o < (params[2] - 1)) && (p < (pnum + 1)); i++)
     {
	if ((!inesc) && (!insub))
	  {
	     if      (s1[i] == '\\') inesc = 1;
	     else if (s1[i] == '%')  insub = 1;
	     if ((!inesc) && (!insub))
	       {
		  s2[o] = s1[i];
		  o++;
	       }
	  }
	else
	  {
	     Embryo_Cell *cptr;

	     if (inesc)
	       {
		  switch (s1[i])
		    {
		     case 't':
		       s2[o] = '\t';
		       o++;
		       break;
		     case 'n':
		       s2[o] = '\n';
		       o++;
		       break;
		     default:
		       s2[o] = s1[i];
		       o++;
		       break;
		    }
		  inesc = 0;
	       }
	     if ((insub) && (s1[i] == '%')) pnum++;
	     if ((insub) && (p < pnum))
	       {
		  switch (s1[i])
		    {
		     case '%':
		       s2[o] = '%';
		       o++;
		       break;
		     case 'c':
		       cptr = embryo_data_address_get(ep, params[4 + p]);
		       if (cptr) s2[o] = (char)(*cptr);
		       p++;
		       o++;
		       break;
		     case 'i':
		     case 'd':
		     case 'x':
		     case 'X':
			 {
			    char fmt[10] = "";
			    char tmp[256] = "";
			    int l;

			    if      (s1[i] == 'i') strcpy(fmt, "%i");
			    else if (s1[i] == 'd') strcpy(fmt, "%d");
			    else if (s1[i] == 'x') strcpy(fmt, "%x");
			    else if (s1[i] == 'X') strcpy(fmt, "%08x");
			    cptr = embryo_data_address_get(ep, params[4 + p]);
			    if (cptr) snprintf(tmp, sizeof(tmp), fmt, (int)(*cptr));
			    l = strlen(tmp);
			    if ((o + l) > (params[2] - 1))
			      {
				 l = params[2] - 1 - o;
				 if (l < 0) l = 0;
				 tmp[l] = 0;
			      }
			    strcpy(s2 + o, tmp);
			    o += l;
			    p++;
			 }
		       break;
		     case 'f':
			 {
			    char tmp[256] = "";
			    int l;

			    cptr = embryo_data_address_get(ep, params[4 + p]);
			    if (cptr) snprintf(tmp, sizeof(tmp), "%f", (double)EMBRYO_CELL_TO_FLOAT(*cptr));
			    l = strlen(tmp);
			    if ((o + l) > (params[2] - 1))
			      {
				 l = params[2] - 1 - o;
				 if (l < 0) l = 0;
				 tmp[l] = 0;
			      }
			    strcpy(s2 + o, tmp);
			    o += l;
			    p++;
			 }
		       break;
		     case 's':
			 {
			    char *tmp;
			    int l;

			    STRGET(ep, tmp, params[4 + p]);
			    l = strlen(tmp);
			    if ((o + l) > (params[2] - 1))
			      {
				 l = params[2] - 1 - o;
				 if (l < 0) l = 0;
				 tmp[l] = 0;
			      }
			    strcpy(s2 + o, tmp);
			    o += l;
			    p++;
			 }
		       break;
		     default:
		       break;
		    }
		  insub = 0;
	       }
	     else if (insub)
	       insub = 0;
	  }
     }
   s2[o] = 0;

   STRSET(ep, params[1], s2);
   return o;
}
Esempio n. 10
0
/*
 * Allocate and fill in the interfaces global variable with the
 * machine's ip addresses and netmasks.
 */
void
load_interfaces()
{
    struct ifconf *ifconf;
    struct ifreq *ifr, ifr_tmp;
    struct sockaddr_in *sin;
    int sock, n, i;
    size_t len = sizeof(struct ifconf) + BUFSIZ;
    char *previfname = "", *ifconf_buf = NULL;
#ifdef _ISC
    struct strioctl strioctl;
#endif /* _ISC */

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
	error(1, "cannot open socket");

    /*
     * Get interface configuration or return (leaving num_interfaces == 0)
     */
    for (;;) {
	ifconf_buf = erealloc(ifconf_buf, len);
	ifconf = (struct ifconf *) ifconf_buf;
	ifconf->ifc_len = len - sizeof(struct ifconf);
	ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));

#ifdef _ISC
	STRSET(SIOCGIFCONF, (caddr_t) ifconf, len);
	if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
#else
	/* Note that some kernels return EINVAL if the buffer is too small */
	if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL) {
#endif /* _ISC */
	    efree(ifconf_buf);
	    (void) close(sock);
	    return;
	}

	/* Break out of loop if we have a big enough buffer. */
	if (ifconf->ifc_len + sizeof(struct ifreq) < len)
	    break;
	len += BUFSIZ;
    }

    /* Allocate space for the maximum number of interfaces that could exist. */
    if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
	return;
    interfaces = (struct interface *) emalloc2(n, sizeof(struct interface));

    /* For each interface, store the ip address and netmask. */
    for (i = 0; i < ifconf->ifc_len; ) {
	/* Get a pointer to the current interface. */
	ifr = (struct ifreq *) &ifconf->ifc_buf[i];

	/* Set i to the subscript of the next interface. */
	i += sizeof(struct ifreq);
#ifdef HAVE_SA_LEN
	if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
	    i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
#endif /* HAVE_SA_LEN */

	/* Skip duplicates and interfaces with NULL addresses. */
	sin = (struct sockaddr_in *) &ifr->ifr_addr;
	if (sin->sin_addr.s_addr == 0 ||
	    strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
	    continue;

	if (ifr->ifr_addr.sa_family != AF_INET)
		continue;

#ifdef SIOCGIFFLAGS
	zero_bytes(&ifr_tmp, sizeof(ifr_tmp));
	strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0)
#endif
	    ifr_tmp = *ifr;
	
	/* Skip interfaces marked "down" and "loopback". */
	if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
	    ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
		continue;

	sin = (struct sockaddr_in *) &ifr->ifr_addr;
	interfaces[num_interfaces].addr.ip4.s_addr = sin->sin_addr.s_addr;

	/* Stash the name of the interface we saved. */
	previfname = ifr->ifr_name;

	/* Get the netmask. */
	zero_bytes(&ifr_tmp, sizeof(ifr_tmp));
	strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
#ifdef SIOCGIFNETMASK
#ifdef _ISC
	STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
	if (ioctl(sock, I_STR, (caddr_t) &strioctl) == 0) {
#else
	if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) == 0) {
#endif /* _ISC */
	    sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;

	    interfaces[num_interfaces].netmask.ip4.s_addr = sin->sin_addr.s_addr;
	} else {
#else
	{
#endif /* SIOCGIFNETMASK */
	    if (IN_CLASSC(interfaces[num_interfaces].addr.ip4.s_addr))
		interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSC_NET);
	    else if (IN_CLASSB(interfaces[num_interfaces].addr.ip4.s_addr))
		interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSB_NET);
	    else
		interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSA_NET);
	}

	/* Only now can we be sure it was a good/interesting interface. */
	interfaces[num_interfaces].family = AF_INET;
	num_interfaces++;
    }

    /* If the expected size < real size, realloc the array. */
    if (n != num_interfaces) {
	if (num_interfaces != 0)
	    interfaces = (struct interface *) erealloc3(interfaces,
		num_interfaces, sizeof(struct interface));
	else
	    efree(interfaces);
    }
    efree(ifconf_buf);
    (void) close(sock);
}

#else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */

/*
 * Stub function for those without SIOCGIFCONF
 */
void
load_interfaces()
{
    return;
}

#endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */

void
dump_interfaces()
{
    int i;
#ifdef HAVE_IN6_ADDR
    char addrbuf[INET6_ADDRSTRLEN], maskbuf[INET6_ADDRSTRLEN];
#endif

    puts("Local IP address and netmask pairs:");
    for (i = 0; i < num_interfaces; i++) {
	switch(interfaces[i].family) {
	    case AF_INET:
		printf("\t%s / ", inet_ntoa(interfaces[i].addr.ip4));
		puts(inet_ntoa(interfaces[i].netmask.ip4));
		break;
#ifdef HAVE_IN6_ADDR
	    case AF_INET6:
		inet_ntop(AF_INET6, &interfaces[i].addr.ip6,
		    addrbuf, sizeof(addrbuf));
		inet_ntop(AF_INET6, &interfaces[i].netmask.ip6,
		    maskbuf, sizeof(maskbuf));
		printf("\t%s / %s\n", addrbuf, maskbuf);
		break;
#endif /* HAVE_IN6_ADDR */
	}
    }
}
Esempio n. 11
0
/*
 * Allocate and fill in the interfaces global variable with the
 * machine's ip addresses and netmasks.
 */
int
get_net_ifs(char **addrinfo)
{
    struct ifconf *ifconf;
    struct ifreq *ifr, ifr_tmp;
    struct sockaddr_in *sin;
    int ailen, i, len, n, sock, num_interfaces = 0;
    size_t buflen = sizeof(struct ifconf) + BUFSIZ;
    char *cp, *previfname = "", *ifconf_buf = NULL;
#ifdef _ISC
    struct strioctl strioctl;
#endif /* _ISC */
    debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
	error(1, _("unable to open socket"));

    /*
     * Get interface configuration or return.
     */
    for (;;) {
	ifconf_buf = emalloc(buflen);
	ifconf = (struct ifconf *) ifconf_buf;
	ifconf->ifc_len = buflen - sizeof(struct ifconf);
	ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));

#ifdef _ISC
	STRSET(SIOCGIFCONF, (caddr_t) ifconf, buflen);
	if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0)
#else
	/* Note that some kernels return EINVAL if the buffer is too small */
	if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL)
#endif /* _ISC */
	    goto done;

	/* Break out of loop if we have a big enough buffer. */
	if (ifconf->ifc_len + sizeof(struct ifreq) < buflen)
	    break;
	buflen += BUFSIZ;
	efree(ifconf_buf);
    }

    /* Allocate space for the maximum number of interfaces that could exist. */
    if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
	debug_return_int(0);
    ailen = n * 2 * INET6_ADDRSTRLEN;
    *addrinfo = cp = emalloc(ailen);

    /* For each interface, store the ip address and netmask. */
    for (i = 0; i < ifconf->ifc_len; ) {
	/* Get a pointer to the current interface. */
	ifr = (struct ifreq *) &ifconf->ifc_buf[i];

	/* Set i to the subscript of the next interface. */
	i += sizeof(struct ifreq);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
	if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
	    i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */

	/* Skip duplicates and interfaces with NULL addresses. */
	sin = (struct sockaddr_in *) &ifr->ifr_addr;
	if (sin->sin_addr.s_addr == 0 ||
	    strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
	    continue;

	if (ifr->ifr_addr.sa_family != AF_INET)
		continue;

#ifdef SIOCGIFFLAGS
	memset(&ifr_tmp, 0, sizeof(ifr_tmp));
	strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0)
#endif
	    ifr_tmp = *ifr;
	
	/* Skip interfaces marked "down" and "loopback". */
	if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
	    ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
		continue;

	sin = (struct sockaddr_in *) &ifr->ifr_addr;
	len = snprintf(cp, ailen - (*addrinfo - cp),
	    "%s%s/", cp == *addrinfo ? "" : " ",
	    inet_ntoa(sin->sin_addr));
	if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
	    warningx(_("load_interfaces: overflow detected"));
	    goto done;
	}
	cp += len;

	/* Stash the name of the interface we saved. */
	previfname = ifr->ifr_name;

	/* Get the netmask. */
	memset(&ifr_tmp, 0, sizeof(ifr_tmp));
	strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
#ifdef _ISC
	STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
	if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
#else
	if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) < 0) {
#endif /* _ISC */
	    sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
	    sin->sin_addr.s_addr = htonl(IN_CLASSC_NET);
	}
	sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
	len = snprintf(cp, ailen - (*addrinfo - cp),
	    "%s", inet_ntoa(sin->sin_addr));
	if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
	    warningx(_("load_interfaces: overflow detected"));
	    goto done;
	}
	cp += len;
	num_interfaces++;
    }

done:
    efree(ifconf_buf);
    (void) close(sock);

    debug_return_int(num_interfaces);
}

#else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */

/*
 * Stub function for those without SIOCGIFCONF or getifaddrs()
 */
int
get_net_ifs(char **addrinfo)
{
    debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
    debug_return_int(0);
}