#include <stdio.h>
#include <memory.h>
#include <ctype.h>
#include "nsaddr.h"
#define toupper(c) (islower(c) ? _toupper(c) : (c))
#define todigit(c) ((int)((c) - '0'))
#define toxdigit(c) ((isdigit(c))?todigit(c):(toupper(c)-(int)'A'+10))
#define isodigit(c) (isdigit(c) && ((c) != '9') && ((c) != '8'))
#define itoac(i) (((i) > 9) ? ((char)((i)-10) + 'A'):((char)(i) + '0'))
#define MASK(n) ((1 << (n)) - 1)
#define MAXRLEVEL 10
#define TRUE 1;
#define FALSE 0;
char scanbuf[SBUFSIZE];
int sbp = 0;
int rec = 0;
char sbuf[SBUFSIZE];
extern void free();
struct netbuf *
stoa(str, addr)
char *str;
struct netbuf *addr;
{
char *xfer(), *prescan();
int myadr;
int quote;
myadr = FALSE;
if (!str)
return NULL;
while (*str && isspace(*str))
++str;
str = prescan(str);
if (!str || !*str) return NULL;
if (!addr) {
if ((addr = (struct netbuf *)malloc(sizeof(struct netbuf))) == NULL)
return NULL;
myadr = TRUE;
addr->buf = NULL;
addr->maxlen = 0;
addr->len = 0;
}
quote = 0;
if (*str == '\\') {
++str;
switch (*str) {
case 'X':
case 'x':
addr->len = dobase(++str, sbuf, HEX);
break;
case 'o':
case 'O':
addr->len = dobase(++str, sbuf, OCT);
break;
case '\0':
addr->len = dostring(str, sbuf, 0);
break;
default:
addr->len = dostring(--str, sbuf, quote);
break;
}
}
else {
if (*str == '"') {
quote = 1;
++str;
}
addr->len = dostring(str, sbuf, quote);
}
if (addr->len == 0) {
if (myadr)
free(addr);
return NULL;
}
if ((addr->buf = xfer(addr->buf, sbuf, addr->len, addr->maxlen)) == NULL)
return NULL;
else
return addr;
}
int
dostring(s, buf, quote)
char *s, *buf;
int quote;
{
char *xcmd();
int oc, ch, len = 0;
int l = 0;
char *rout;
while (*s) {
if (len >= SBUFSIZE) {
fprintf(stderr, "dostring: string too long\n");
break;
}
else if (*s == '\\')
switch(*++s) {
case '!':
if (rout = xcmd(s+1, '!', &s, &l)) {
if (len + l < SBUFSIZE)
memcpy(buf+len, rout, l);
len += l;
free(rout);
}
break;
case '\n':
++s;
break;
case 'b':
buf[len++] = '\b'; s++;
break;
case 'n':
buf[len++] = '\n'; s++;
break;
case 'r':
buf[len++] = '\r'; s++;
break;
case 't':
buf[len++] = '\t'; s++;
break;
case 'v':
buf[len++] = '\v'; s++;
case '0':
case '1':
case '2':
case '3':
for(oc=ch=0; (*s >= '0' && *s <= '7') && oc++ < 3; ++s)
ch = (ch << 3) | (*s - '0');
buf[len++] = ch;
break;
case 0:
break;
default:
buf[len++] = *s++;
break;
}
else if ((quote && (*s == '"')) || (!quote && isspace(*s)))
break;
else
buf[len++] = *s++;
}
return (len >= SBUFSIZE) ? 0 : len;
}
int
dobase(s, buf, type)
char *s, *buf;
int type;
{
void memcp();
int bp = SBUFSIZE - 1;
int shift = 0;
char *end;
for (end = s; *end && ((type == OCT) ? isodigit(*end) :
isxdigit(*end)); ++end) ;
if ((*s == 0) || (end == s) || (!isspace(*end) && *end)) {
fprintf(stderr, "dobase: Illegal trailer on address string\n");
buf[0] = '\0';
return 0;
}
--end;
buf[bp] = '\0';
while (bp > 0 && end >= s) {
buf[bp] |= toxdigit(*end) << shift;
if (type == OCT) {
if (shift > 5) {
buf[--bp] = (todigit(*end) >> (8 - shift))
& MASK(shift-5);
}
if ((shift = (shift + 3) % 8) == 0)
buf[--bp] = 0;
}
else
if ((shift = (shift) ? 0 : 4) == 0)
buf[--bp] = 0;;
--end;
}
if (bp == 0) {
fprintf(stderr, "stoa: dobase: number to long\n");
return 0;
}
if (!shift)
bp++;
memcp(buf, &buf[bp], (SBUFSIZE - bp));
return (SBUFSIZE - bp);
}
#ifdef NOTUSED
char *
atos(str, addr, type)
char *str;
struct netbuf *addr;
int type;
{
char *xfer();
int mystr = 0;
unsigned x_atos(), o_atos();
void memcp();
char *base;
if (addr == NULL)
return NULL;
if (str == NULL)
if ((str = malloc(SBUFSIZE)) == NULL)
return NULL;
else
mystr = 1;
switch (type) {
case OCT:
sbuf[0] = '\\';
sbuf[1] = 'o';
return xfer(str, sbuf, o_atos(sbuf+2, addr->buf, addr->len) + 2,
mystr ? SBUFSIZE : 0);
case HEX:
sbuf[0] = '\\';
sbuf[1] = 'x';
return xfer(str, sbuf, x_atos(sbuf+2, addr->buf, addr->len) + 2,
mystr ? SBUFSIZE : 0);
case RAW:
base = xfer(str, addr->buf,
addr->len + 1, mystr ? SBUFSIZE : 0);
if (base)
base[addr->len] = '\0';
return base;
default:
return NULL;
}
}
unsigned
x_atos(s, a, l)
char *s, *a;
unsigned l;
{
char *b;
b = s;
while (l--) {
*s++ = itoac(((*a >> 4) & MASK (4)));
*s++ = itoac((*a & MASK(4)));
++a;
}
*s = '\0';
return (s - b + 1);
}
unsigned
o_atos(s, a, l)
char *s, *a;
unsigned l;
{
int i, shift;
char *b;
b = s;
if (l == 0) {
*s = '\0';
return 0;
}
i = l % 3;
*s++ = itoac((*a>>(i+5)) & MASK(3-i));
shift = 2 + i;
while (l)
if (shift <= 5) {
*s++ = itoac((*a >> shift) & MASK(3));
if (shift == 0) {
++a;
--l;
}
shift += (shift < 3) ? 5 : -3;
}
else {
i = (*a & MASK(shift-5)) << (8-shift);
i |= (*++a >> shift) & MASK(8-shift);
*s++ = itoac(i);
shift -= 3;
--l;
}
*s++ = '\0';
return (s - b + 1);
}
#endif
void
memcp(d, s, n)
char *d, *s;
int n;
{
while (n--)
*d++ = *s++;
}
char *
xfer(dest, src, len, max)
char *dest, *src;
unsigned len, max;
{
if (max && dest && max < len) {
fprintf(stderr, "xfer: destination not long enough\n");
return NULL;
}
if (!dest)
if ((dest = (char *)malloc(len)) == NULL) {
fprintf(stderr, "xfer: malloc failed\n");
return NULL;
}
memcpy(dest, src, (int)len);
return dest;
}
char *
prescan(s)
char *s;
{
int scan();
rec = sbp = 0;
if (!s || !*s || !scan(s))
return NULL;
scanbuf[sbp] = '\0';
return scanbuf;
}
int
scan(s)
char *s;
{
char *xcmd();
char *cmd;
int len;
int esc = 0;
while (*s) {
if (!esc && (*s == '\\' && *(s+1) == '$')) {
if (rec++ == MAXRLEVEL) {
fprintf(stderr, "scan: Recursion \
level past %d on shell escape\n", rec);
return 0;
}
if ((cmd = xcmd(s+2, '$', &s, &len)) != NULL) {
cmd[len] = '\0';
if (*cmd != '\0')
scan(cmd);
free(cmd);
}
else
return 0;
}
else if (sbp == SBUFSIZE) {
fprintf(stderr, "Overflow on shell esc expansion\n");
return 0;
}
else if (sbp < SBUFSIZE)
esc = ((scanbuf[sbp++] = *s++) == '\\');
}
return 1;
}
char *
xcmd(s, ec, ps, len)
char *s;
char ec;
char **ps;
int *len;
{
FILE *popen();
int pclose();
FILE *pfp;
char *cmd;
char *cmdp;
char *ocmd;
int esc = 0;
*len = 0;
if ((cmd = cmdp = (char *)malloc(SBUFSIZE)) == NULL) {
fprintf(stderr, "xcmd: malloc failed\n");
return NULL;
}
if ((ocmd = (char *)malloc(SBUFSIZE)) == NULL) {
fprintf(stderr, "xcmd: malloc failed\n");
free(cmd);
return NULL;
}
while (*s) {
if (!esc && *s == '\\' && *(s+1) == ec) {
s += 2;
break;
}
else
esc = (*cmdp++ = *s++) == '\\';
}
*cmdp = '\0';
*ps = s;
if ((pfp = popen(cmd, "r")) == NULL)
fprintf(stderr, "xcmd: popen failed\n");
while (fread(&ocmd[*len], 1, 1, pfp))
if ((*len += 1) >= SBUFSIZE) {
fprintf(stderr, "xcmd: command output too long\n");
break;
}
pclose(pfp);
free(cmd);
return ocmd;
}