/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 *
 */
/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley Software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#ifndef lint
static char *sccsid = "@(#)sh.err.c	5.3 (Berkeley) 5/13/86";
#endif

#include "sh.h"
#include <sys/ioctl.h>

/*
 * C Shell
 */

bool	errspl;			/* Argument to error was spliced by seterr2 */
char	one[2] = { '1', 0 };
char	*onev[2] = { one, NOSTR };
extern	sys_nerr;
extern	char *sys_errlist[];
extern  char * _gettxt();
/*
 * Print error string s with optional argument arg.
 * This routine always resets or exits.  The flag haderr
 * is set so the routine who catches the unwind can propogate
 * it if they want.
 *
 * Note that any open files at the point of error will eventually
 * be closed in the routine process in sh.c which is the only
 * place error unwinds are ever caught.
 */
/*VARARGS1*/
error(s, arg)
	char *s;
{
	register char **v;
	register char *ep;

	/*
	 * Must flush before we print as we wish output before the error
	 * to go on (some form of) standard output, while output after
	 * goes on (some form of) diagnostic output.
	 * If didfds then output will go to 1/2 else to FSHOUT/FSHDIAG.
	 * See flush in sh.print.c.
	 */
	flush();
	haderr = 1;		/* Now to diagnostic output */
	timflg = 0;		/* This isn't otherwise reset */
	if (v = pargv)
		pargv = 0, blkfree(v);
	if (v = gargv)
		gargv = 0, blkfree(v);

	/*
	 * A zero arguments causes no printing, else print
	 * an error diagnostic here.
	 */
	if (s)
		printf(s, arg), printf(".\n");

	didfds = 0;		/* Forget about 0,1,2 */
	if ((ep = err) && errspl) {
		errspl = 0;
		xfree(ep);
	}
	errspl = 0;

	/*
	 * Go away if -e or we are a child shell
	 */
	if (exiterr || child)
		exit(1);

	/*
	 * Reset the state of the input.
	 * This buffered seek to end of file will also
	 * clear the while/foreach stack.
	 */
	btoeof();

	setq("status", onev, &shvhed);
	if (tpgrp > 0) {
		(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&tpgrp);
#ifdef PROCDEBUG
		dprintf("error: ioctl(FSHTTY, TIOCSPGRP, %d)", tpgrp);
#endif
	}
	reset();		/* Unwind */
}

/*
 * Perror is the shells version of perror which should otherwise
 * never be called.
 */
Perror(s)
	char *s;
{
	void xperror();

	/*
	 * Perror uses unit 2, thus if we didn't set up the fd's
	 * we must set up unit 2 now else the diagnostic will disappear
	 */
	if (!didfds) {
		register int oerrno = errno;

		(void) dcopy(SHDIAG, 2);
		errno = oerrno;
	}
	(void) xperror(s);
	error(NOSTR);		/* To exit or unwind */
}

/*
 *  xperror is a special handy dandy version of perror that we include
 *  here in our wonderful csh source since the source contains its own
 *  version of doprnt.  A problem arose when using the standard perror()
 *  because the sprintf() call in perror() called the csh version of doprnt()
 *  instead of the standard doprnt().  Bad perror.  This version of xperror
 *  does some really, really, kludgy stuff to duplicate the sprintf() call.
 *  Gag me with a chainsaw.
 */
void
xperror(s)
char    *s;
{
        register char *c;
        register int n;
        register unsigned  m;

        c = _gettxt("libc:1", "Unknown error");
        if(errno >= 0 && errno < sys_nerr) {
                char msgid[12], bob[4], *bob2;
		int i=0, temp=0;
		temp = errno+1;
		strcpy(msgid,"syserr:");
		while (temp) {
			bob[i++] = '0' + (temp % 10);
			temp /= 10;
		}
		bob2 = &msgid[7];
		while (i)
			*bob2++ = bob[--i];
		*bob2 = '\0';
/*
                sprintf(msgid,"syserr:%d", errno+1);
*/
                c = _gettxt(msgid, sys_errlist[errno]);
        }
        n = strlen(s);
        if(n) {
                (void) write(2, s, (unsigned)n);
                (void) write(2, ": ", 2);
        }
        m = (unsigned)strlen(c);
        (void) write(2, c, m);
        (void) write(2, "\n", 1);
}



bferr(cp)
	char *cp;
{

	flush();
	haderr = 1;
	printf("%s: ", bname);
	error(cp);
}

/*
 * The parser and scanner set up errors for later by calling seterr,
 * which sets the variable err as a side effect; later to be tested,
 * e.g. in process.
 */
seterr(s)
	char *s;
{

	if (err == 0)
		err = s, errspl = 0;
}

/* Set err to a splice of cp and dp, to be freed later in error() */
seterr2(cp, dp)
	char *cp, *dp;
{

	if (err)
		return;
	err = strspl(cp, dp);
	errspl++;
}

/* Set err to a splice of cp with a string form of character d */
seterrc(cp, d)
	char *cp, d;
{
	char chbuf[2];

	chbuf[0] = d;
	chbuf[1] = 0;
	seterr2(cp, chbuf);
}
