root/usr/src/cmd/sgs/error/common/errorsubr.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#include "error.h"

/*
 *      Arrayify a list of rules
 */
void
arrayify(int *e_length, Eptr **e_array, Eptr header)
{
        Eptr    errorp;
        Eptr    *array;
        int     listlength;
        int     listindex;

        for (errorp = header, listlength = 0;
            errorp; errorp = errorp->error_next, listlength++)
                continue;
        array = Calloc(listlength+1, sizeof (Eptr));
        for (listindex = 0, errorp = header;
            listindex < listlength;
            listindex++, errorp = errorp->error_next) {
                array[listindex] = errorp;
                errorp->error_position = listindex;
        }
        array[listindex] = (Eptr)0;
        *e_length = listlength;
        *e_array = array;
}

/*PRINTFLIKE1*/
static void
error(char *format, ...)
{
        va_list args;

        va_start(args, format);
        (void) fprintf(stderr, "Error: ");
        (void) vfprintf(stderr, format, args);
        (void) fprintf(stderr, "\n");
        (void) fflush(stdout);
        (void) fflush(stderr);
        va_end(args);
        exit(6);
}

void *
Calloc(int nelements, int size)
{
        void    *back;
        if ((back = calloc(nelements, size)) == NULL) {
                error("Ran out of memory.\n");
                exit(1);
        }
        return (back);
}

char *
strsave(char *instring)
{
        char    *outstring;
        (void) strcpy(outstring = Calloc(1, strlen(instring) + 1),
            instring);
        return (outstring);
}
/*
 *      find the position of a given character in a string
 *              (one based)
 */
int
position(char *string, char ch)
{
        int     i;

        if (string) {
                for (i = 1; *string; string++, i++) {
                        if (*string == ch)
                                return (i);
                }
        }
        return (-1);
}
/*
 *      clobber the first occurance of ch in string by the new character
 */
char *
substitute(char *string, char chold, char chnew)
{
        char    *cp = string;

        if (cp) {
                while (*cp) {
                        if (*cp == chold) {
                                *cp = chnew;
                                break;
                        }
                        cp++;
                }
        }
        return (string);
}

char
lastchar(char *string)
{
        int     length;

        if (string == NULL)
                return ('\0');
        length = strlen(string);
        if (length >= 1)
                return (string[length-1]);
        else
                return ('\0');
}

char
firstchar(char *string)
{
        if (string)
                return (string[0]);
        else
                return ('\0');
}

char
next_lastchar(char *string)
{
        int     length;

        if (string == NULL)
                return ('\0');
        length = strlen(string);
        if (length >= 2)
                return (string[length - 2]);
        else
                return ('\0');
}

void
clob_last(char *string, char newstuff)
{
        int     length = 0;
        if (string)
                length = strlen(string);
        if (length >= 1)
                string[length - 1] = newstuff;
}

/*
 *      parse a string that is the result of a format %s(%d)
 *      return TRUE if this is of the proper format
 */
boolean
persperdexplode(char *string, char **r_perd, char **r_pers)
{
        char    *cp;
        int     length = 0;

        if (string)
                length = strlen(string);
        if ((length >= 4) && (string[length - 1] == ')')) {
                for (cp = &string[length - 2];
                    (isdigit(*cp)) && (*cp != '('); --cp)
                        continue;
                if (*cp == '(') {
                        string[length - 1] = '\0';      /* clobber the ) */
                        *r_perd = strsave(cp+1);
                        string[length - 1] = ')';
                        *cp = '\0';                     /* clobber the ( */
                        *r_pers = strsave(string);
                        *cp = '(';
                        return (TRUE);
                }
        }
        return (FALSE);
}

static  char    cincomment[] = CINCOMMENT;
static  char    coutcomment[] = COUTCOMMENT;
static  char    fincomment[] = FINCOMMENT;
static  char    foutcomment[] = FOUTCOMMENT;
static  char    newline[] = NEWLINE;
static  char    piincomment[] = PIINCOMMENT;
static  char    pioutcomment[] = PIOUTCOMMENT;
static  char    lispincomment[] = LISPINCOMMENT;
static  char    riincomment[] = RIINCOMMENT;
static  char    rioutcomment[] = RIOUTCOMMENT;
static  char    troffincomment[] = TROFFINCOMMENT;
static  char    troffoutcomment[] = TROFFOUTCOMMENT;
static  char    mod2incomment[] = MOD2INCOMMENT;
static  char    mod2outcomment[] = MOD2OUTCOMMENT;

struct lang_desc lang_table[] = {
        /* INUNKNOWN    0 */    "unknown", cincomment,  coutcomment,
        /* INCPP        1 */    "cpp",  cincomment,    coutcomment,
        /* INCC         2 */    "cc",   cincomment,    coutcomment,
        /* INAS         3 */    "as",   ASINCOMMENT,   newline,
        /* INLD         4 */    "ld",   cincomment,    coutcomment,
        /* INLINT       5 */    "lint", cincomment,    coutcomment,
        /* INF77        6 */    "f77",  fincomment,    foutcomment,
        /* INPI         7 */    "pi",   piincomment,   pioutcomment,
        /* INPC         8 */    "pc",   piincomment,   pioutcomment,
        /* INFRANZ      9 */    "franz", lispincomment, newline,
        /* INLISP       10 */   "lisp", lispincomment, newline,
        /* INVAXIMA     11 */   "vaxima", lispincomment, newline,
        /* INRATFOR     12 */   "ratfor", fincomment,   foutcomment,
        /* INLEX        13 */   "lex",  cincomment,    coutcomment,
        /* INYACC       14 */   "yacc", cincomment,    coutcomment,
        /* INAPL        15 */   "apl",  ".lm", newline,
        /* INMAKE       16 */   "make", ASINCOMMENT,   newline,
        /* INRI         17 */   "ri",   riincomment,   rioutcomment,
        /* INTROFF      18 */   "troff", troffincomment, troffoutcomment,
        /* INMOD2       19 */   "mod2", mod2incomment, mod2outcomment,
        /* INSUNF77     20 */   "Sunf77", fincomment,   foutcomment,
        0,      0,      0
};

void
printerrors(boolean look_at_subclass, int errorc, Eptr errorv[])
{
        int     i;
        Eptr    errorp;

        for (errorp = errorv[i = 0]; i < errorc; errorp = errorv[++i]) {
                if (errorp->error_e_class == C_IGNORE)
                        continue;
                if (look_at_subclass && errorp->error_s_class == C_DUPL)
                        continue;
                (void) printf("Error %d, (%s error) [%s], text = \"",
                    i,
                    class_table[errorp->error_e_class],
                    lang_table[errorp->error_language].lang_name);
                wordvprint(stdout, errorp->error_lgtext, errorp->error_text);
                (void) printf("\"\n");
        }
}

void
wordvprint(FILE *fyle, int wordc, char *wordv[])
{
        int     i;
        char *sep = "";

        for (i = 0; i < wordc; i++)
                if (wordv[i]) {
                        (void) fprintf(fyle, "%s%s", sep, wordv[i]);
                        sep = " ";
                }
}

/*
 *      Given a string, parse it into a number of words, and build
 *      a wordc wordv combination pointing into it.
 */
void
wordvbuild(char *string, int *r_wordc, char ***r_wordv)
{
        char    *cp;
        char    *saltedbuffer;
        char    **wordv;
        int     wordcount;
        int     wordindex;

        saltedbuffer = strsave(string);
        for (wordcount = 0, cp = saltedbuffer; *cp; wordcount++) {
                while (*cp && isspace(*cp))
                        cp++;
                if (*cp == 0)
                        break;
                while (*cp && !isspace(*cp))
                        cp++;
        }
        wordv = Calloc(wordcount + 1, sizeof (char *));
        for (cp = saltedbuffer, wordindex = 0; wordcount;
            wordindex++, --wordcount) {
                while (*cp && isspace(*cp))
                        cp++;
                if (*cp == 0)
                        break;
                wordv[wordindex] = cp;
                while (*cp && !isspace(*cp))
                        cp++;
                *cp++ = '\0';
        }
        if (wordcount != 0)
                error("Initial miscount of the number of words in a line\n");
        wordv[wordindex] = NULL;
#ifdef FULLDEBUG
        for (wordcount = 0; wordcount < wordindex; wordcount++)
                (void) printf("Word %d = \"%s\"\n", wordcount,
                    wordv[wordcount]);
        (void) printf("\n");
#endif
        *r_wordc = wordindex;
        *r_wordv = wordv;
}
/*
 *      Compare two 0 based wordvectors
 */
int
wordvcmp(char **wordv1, int wordc, char **wordv2)
{
        int i;
        int     back;

        for (i = 0; i < wordc; i++) {
                if (wordv1[i] == 0 || wordv2[i] == 0)
                                return (-1);
                if (back = strcmp(wordv1[i], wordv2[i])) {
                        return (back);
                }
        }
        return (0);     /* they are equal */
}

/*
 *      splice a 0 basedword vector onto the tail of a
 *      new wordv, allowing the first emptyhead slots to be empty
 */
char **
wordvsplice(int emptyhead, int wordc, char **wordv)
{
        char    **nwordv;
        int     nwordc = emptyhead + wordc;
        int     i;

        nwordv = Calloc(nwordc, sizeof (char *));
        for (i = 0; i < emptyhead; i++)
                nwordv[i] = 0;
        for (i = emptyhead; i < nwordc; i++) {
                nwordv[i] = wordv[i-emptyhead];
        }
        return (nwordv);
}

/*
 *      plural'ize and verb forms
 */
static  char    *S = "s";
static  char    *N = "";

char *
plural(int n)
{
        return (n > 1 ? S : N);
}

char *
verbform(int n)
{
        return (n > 1 ? N : S);
}