/*
 * Miscellaneous functions
 */

static char *RCSid = "$Header: misc.c,v 3.1 88/11/03 09:17:14 egisin Exp $";

#include <stddef.h>
#include <limits.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include "sh.h"
#include "expand.h"

char ctypes [UCHAR_MAX];	/* type bits for unsigned char */

/*
 * Fast character classes
 */
void
setctypes(s, t)
	register Const char *s;
	register int t;
{
	register int i;

	if ((t&C_IFS)) {
		for (i = 0; i < UCHAR_MAX; i++)
			ctypes[i] &=~ C_IFS;
		ctypes[0] |= C_IFS; /* include \0 in C_IFS */
	}
	ctypes[(unsigned char) *s++] |= t;	/* allow leading \0 in string */
	while (*s != 0)
		ctypes[(unsigned char) *s++] |= t;
}

void
initctypes()
{
	register int c;

	for (c = 'a'; c <= 'z'; c++)
		ctypes[c] |= C_ALPHA;
	for (c = 'A'; c <= 'Z'; c++)
		ctypes[c] |= C_ALPHA;
	ctypes['_'] |= C_ALPHA;
	setctypes("0123456789", C_DIGIT);
	setctypes("\0 \t\n|&;<>()", C_LEX1);
	setctypes("*@#!$-?", C_VAR1);
	setctypes("=-+?#%", C_SUBOP);
}

/* convert unsigned long to base N string */

char *
ulton(n, base)
	register unsigned long n;
	int base;
{
	register char *p;
	static char buf [20];

	p = &buf[sizeof(buf)];
	*--p = '\0';
	do {
		*--p = "0123456789ABCDEF"[n%base];
		n /= base;
	} while (n != 0);
	return p;
}

char *
strsave(s, ap)
	register char *s;
	Area *ap;
{
	return strcpy((char*) alloc((size_t)strlen(s)+1, ap), s);
}

static struct option {
	char *name;
	int flag;
} options[] = {
	{"allexport",	FEXPORT},
	{"bgnice",	FBGNICE},
#if EDIT
	{"emacs",	FEMACS},
#endif
	{"errexit",	FERREXIT},
	{"hashall",	FHASHALL},
	{"ignoreeof",	FIGNEOF},
	{"interactive",	FTALKING},
	{"keyword",	FKEYWORD},
	{"markdirs",	FMARKDIRS},
	{"monitor",	FMONITOR},
	{"noexec",	FNOEXEC},
	{"noglob",	FNOGLOB},
	{"nounset",	FNOUNSET},
	{"privileged",	FPRIVILEGED},
	{"stdin",	FSTDIN},
	{"trackall",	FHASHALL},
	{"verbose",	FVERBOSE},
	{"xtrace",	FXTRACE},
	{NULL,		0}
};	

/*
 * translate -o option into F* constant
 */
int
option(n)
	Const char *n;
{
	register struct option *op;

	for (op = options; op->name != NULL; op++)
		if (strcmp(op->name, n) == 0)
			return op->flag;
	return 0;
}

char *
getoptions()
{
	register int c;
	char m [26+1];
	register char *cp = m;

	for (c = 'a'; c <= 'z'; c++)
		if (flag[FLAG(c)])
			*cp++ = (char) c;
	*cp = 0;
	return strsave(m, ATEMP);
}

void
printoptions()
{
	register struct option *op;

	for (op = options; op->name != NULL; op++)
		if (flag[op->flag])
			shellf("%s ", op->name);
	shellf("\n");
}
	
/* atoi with error detection */

getn(as)
	char *as;
{
	register char *s;
	register int n;

	s = as;
	if (*s == '-')
		s++;
	for (n = 0; digit(*s); s++)
		n = (n*10) + (*s-'0');
	if (*s)
		errorf("%s: bad number\n", as);
	return (*as == '-') ? -n : n;
}

/*
 * stripped down strerror for kill and exec
 */
char *
strerror(i)
	int i;
{
	switch (i) {
	  case EINVAL:
		return "Invalid argument";
	  case EACCES:
		return "Permission denied";
	  case ESRCH:
		return "No such process";
	  case EPERM:
		return "Not owner";
	  case ENOENT:
		return "No such file or directory";
	  case ENOTDIR:
		return "Not a directory";
	  case ENOEXEC:
		return "Exec format error";
	  case ENOMEM:
		return "Not enough memory";
	  case E2BIG:
		return "Argument list too long";
	  default:
		return "Unknown system error";
	}
}

xpexpand(xp)
	register XPtrV *xp;
{
	int n = XPsize(*xp);
	Void **vp;
	register Void **dvp, **svp;

	vp = alloc(sizeofN(Void*, n*2), ATEMP);
	for (svp = xp->beg, dvp = vp; svp < xp->cur; )
		*dvp++ = *svp++;
	afree((Void*) xp->beg, ATEMP);
	xp->beg = vp;
	xp->cur = vp + n;
	xp->end = vp + n*2;
}

/* -------- gmatch.c -------- */

/*
 * int gmatch(string, pattern)
 * char *string, *pattern;
 *
 * Match a pattern as in sh(1).
 * pattern character are prefixed with MAGIC by expand.
 */

#define	NOT	'!'	/* might use ^ */

static	char	*cclass ARGS((char *, int c));

int
gmatch(s, p)
	register char *s, *p;
{
	register int sc, pc;

	if (s == NULL || p == NULL)
		return 0;
	while ((pc = *p++) != 0) {
		sc = *s++;
		if (pc ==  MAGIC)
			switch (*p++) {
			  case '[':
				if ((p = cclass(p, sc)) == NULL)
					return (0);
				break;

			  case '?':
				if (sc == 0)
					return (0);
				break;

			  case '*':
				s--;
				do {
					if (*p == '\0' || gmatch(s, p))
						return (1);
				} while (*s++ != '\0');
				return (0);

			}
		else
			if (sc != pc)
				return 0;
	}
	return (*s == 0);
}

static char *
cclass(p, sub)
	register char *p;
	register int sub;
{
	register int c, d, not, found = 0;

	if ((not = *p == NOT))
		p++;
	do {
		if (*p == '\0')
			return NULL;
		c = *p;
		if (p[1] == '-' && p[2] != ']') {
			d = p[2];
			p++;
		} else
			d = c;
		if (c == sub || c <= sub && sub <= d)
			found = 1;
	} while (*++p != ']');

	return (found != not) ? p+1 : NULL;
}

/* -------- qsort.c -------- */

/*
 * quick sort of array of generic pointers to objects.
 */

void
qsortp(base, n, f)
	Void **base;		/* base address */
	size_t n;		/* elements */
	int (*f)();		/* compare function */
{
	qsort1(base, base + n, f);
}

#define	swap2(a, b)	{\
	register Void *t; t = *(a); *(a) = *(b); *(b) = t;\
}
#define	swap3(a, b, c)	{\
	register Void *t; t = *(a); *(a) = *(c); *(c) = *(b); *(b) = t;\
}

qsort1(base, lim, f)
	Void **base, **lim;
	int (*f)();
{
	register Void **i, **j;
	register Void **lptr, **hptr;
	size_t n;
	int c;

  top:
	n = (lim - base) / 2;
	if (n == 0)
		return;
	hptr = lptr = base+n;
	i = base;
	j = lim - 1;

	for (;;) {
		if (i < lptr) {
			if ((c = (*f)(*i, *lptr)) == 0) {
				lptr --;
				swap2(i, lptr);
				continue;
			}
			if (c < 0) {
				i += 1;
				continue;
			}
		}

	  begin:
		if (j > hptr) {
			if ((c = (*f)(*hptr, *j)) == 0) {
				hptr ++;
				swap2(hptr, j);
				goto begin;
			}
			if (c > 0) {
				if (i == lptr) {
					hptr ++;
					swap3(i, hptr, j);
					i = lptr += 1;
					goto begin;
				}
				swap2(i, j);
				j -= 1;
				i += 1;
				continue;
			}
			j -= 1;
			goto begin;
		}

		if (i == lptr) {
			if (lptr-base >= lim-hptr) {
				qsort1(hptr+1, lim, f);
				lim = lptr;
			} else {
				qsort1(base, lptr, f);
				base = hptr+1;
			}
			goto top;
		}

		lptr -= 1;
		swap3(j, lptr, i);
		j = hptr -= 1;
	}
}

int
xstrcmp(p1, p2)
	Void *p1, *p2;
{
	return (strcmp((char *)p1, (char *)p2));
}

