root/usr/src/cmd/csh/sh.err.c
/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
/*        All Rights Reserved   */

/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley Software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#include "sh.h"
#include <locale.h>
#include <dirent.h>
#include <string.h>
/*
 * #include <sys/ioctl.h>
 * #include <stdlib.h>
 */
#include "sh.tconst.h"
/*
 * C Shell
 */

bool    child;
bool    didfds;
bool    exiterr;
bool    errspl;                 /* Argument to error was spliced by seterr2 */
bool    haderr;
jmp_buf reslab;
tchar one[2] = { '1', 0 };
tchar *onev[2] = { one, NOSTR };
short   SHDIAG;
int     tpgrp;

/*
 *    contains DIR * for last opendir_(), its left open if an error
 *    longjmp (reset) occurs before it gets closed via closedir.
 *    if its not null in the error handler, then closedir it.
 */
DIR *Dirp = NULL;

/*
 * 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*/
void
error(s, a1, a2)
     char       *s;
{
        tchar **v;
        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 */
        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, a1, a2), printf("\n");
        }


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

        if ( Dirp ){
                closedir(Dirp);
                Dirp = NULL;
        }

        /*
         * 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(S_status, onev, &shvhed);
        if (tpgrp > 0)
                (void) ioctl(FSHTTY, TIOCSPGRP,  (char *)&tpgrp);
        reset();                /* Unwind */
}

/*
 * Perror is the shells version of perror which should otherwise
 * never be called.
 */
void
Perror(tchar *s)
{
        char    chbuf[BUFSIZ];

        /*
         * 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) {
                int oerrno = errno;

                (void) dcopy(SHDIAG, 2);
                errno = oerrno;
        }
        tstostr(chbuf, s);
        perror(chbuf);
        error(NULL);            /* To exit or unwind */
}

void
bferr(char *cp)
{

        flush();
        haderr = 1;
        if( bname) printf("%t: ", bname);
        error("%s", gettext(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.
 */
void
seterr(char *s)
{

        if (err_msg == NULL)
                err_msg = s, errspl = 0;
}

/* Set err to a splice of cp and dp, to be freed later in error() */
void
seterr2(tchar *cp, char *dp)
{
        char    chbuf[BUFSIZ];
        char    *gdp;

        if (err_msg)
                return;

        /* Concatinate cp and dp in the allocated space. */
        tstostr(chbuf, cp);
        gdp = gettext(dp);
        err_msg = (char *)xalloc(strlen(chbuf)+strlen(gdp)+1);
        strcpy(err_msg, chbuf);
        strcat(err_msg, gdp);

        errspl++;/* Remember to xfree(err_msg). */
}

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

        /* don't overwrite an existing error message */
        if (err_msg)
                return;

#ifdef MBCHAR
        {
        wchar_t wcd=(wchar_t)(d&TRIM);
        int     i;

        i = wctomb(chbuf, wcd); /* chbuf holds d in multibyte representation. */
        chbuf[(i>0)?i:0] = (char) 0;
        }
#else
        chbuf[0]=(char)(d&TRIM); chbuf[1]=(char)0;
#endif


        /* Concatinate cp and d in the allocated space. */
        err_msg = (char *)xalloc(strlen(cp)+strlen(chbuf)+1);
        strcpy(err_msg, cp);
        strcat(err_msg, chbuf);

        errspl++; /* Remember to xfree(err_msg). */
}