Subversion Repositories DevTools

Rev

Blame | Last modification | View Log | RSS feed

/*
        CPP V5 -- utilities.

        Source:  utl.c
        Started: October 7, 1985
        Version:
                July 21, 1988
                March 3, 1989
                        bug fix to skip_ws() and copy_ws().
                August 1, 1989
                        Support for C++ style single-line comments added to
                        skip_pp(), skip_ws() and copy_ws().

        Written by Edward K. Ream.
        This software is in the public domain.

        See the read.me file for disclaimer and other information.
*/

#include "cpp.h"

/*
        Return the value of a character constant.
*/
int
char_val(s)
register char *s;
{
        int val;

        if (*s != '\\') {
                return (int) *s;
        }
        s++;
        switch (*s) {
        case 'b':       return '\b';
        case 'f':       return '\f';
        case 'n':       return '\n';
        case 'r':       return '\r';
        case 't':       return '\t';
        case '\'':      return '\'';
        case '\\':      return '\\';

        default:
                if (*s < '0' || *s > '7') {
                        return (int)*s;
                }
                val = 0;
                while (*s >= '0' && *s <= '7') {
                        val = val * 8 + (int)*s - '0';
                        s++;
                }
                return val;
        }
}

/*
        Re-evaluate a string constant; this may shorten it

        Return its length; it may contain imbedded zeroes once processed

        CAUTION: if the string is transformed, it is always shortened.  Callers
        of this routine may count on that fact.
*/
unsigned int
str_val(d)
register unsigned char *d;
{
        register unsigned char val, *dd, *s;
        TICK("str_val");

        /* outer loop to scan the string */
        s = dd = d;
        while (*s) {
                if (*s != '\\') {
                        *d++ = *s++;
                        continue;
                }
                ++s;
                switch (*s) {
                case 'b':       *d++ = '\b'; ++s; break;
                case 'f':       *d++ = '\f'; ++s; break;
                case 'n':       *d++ = '\n'; ++s; break;
                case 'r':       *d++ = '\r'; ++s; break;
                case 't':       *d++ = '\t'; ++s; break;
                case '\'':      *d++ = '\''; ++s; break;
                case '\\':      *d++ = '\\'; ++s; break;

                default:
                        if (*s < '0' || *s > '7') {
                                continue;
                        }
                        val = 0;
                        while (*s >= '0' && *s <= '7') {
                                val = val * 8 + *s - '0';
                                s++;
                        }
                        *d++ = val;
                }
        }
        *d++ = '\0';
        TRACEP("str_val", printf("returns length %d\n", (int)(d - dd)));
        return (unsigned int)(d - dd);
}

/*
        Return the value of a string of digits in a given radix.
*/
int
conv2i(string, radix)
char *string;
int radix;
{
        register int value;
        register int digit;

        TICK("conv2i");

        value = 0;
        while (digit = *string++) {
                if (digit >= 'a' && digit <= 'z') {
                        digit = digit - 'a' + 10;
                }
                else if (digit >= 'A' && digit <= 'Z') {
                        digit = digit - 'A' + 10;
                }
                else {
                        digit = digit - '0';
                }
                value = (value * radix) + digit;
        }
        return value;
}

/*
        Convert a signed integer n to a string s[].
        The length of s must be large enough to hold the result.
*/
void
conv2s (a, s)
int a;
register char *s;
{
        register char *d, *ss;
        register int sn;
        register unsigned long n;
        char temp [INT_DIGITS];

        TICK("conv2s");

        /* Do the sign and handle 0x8000 correctly */
        if (a >= 0) {
                sn = 0;
                /* these casts ARE NOT redundant: DO NOT fix them! */
                /* see note in lint.doc about unsigned extending casts */
                n = (unsigned long) (long) a;
        }
        else {
                sn = 1;
                n = (unsigned long) (long) (-a);
        }

        /* put digits in reverse order into temp */
        d = &temp[0];
        *d++ = 0;
        if (n) while (n) {
                /* NOTE: in assembly, we would divide once */
                *d++ = (char)(n % 10) + '0';
                n = n / 10;
        }
        else {
                *d++ = '0';
        }

        /* insert the sign */
        if (sn) {
                *d++ = '-';
        }

        /* Reverse temp into s. */
        ss = s;
        while(*ss++ = *--d) {};

        TRACE("conv2s", printf("conv2s returns: %s\n", s));
}

/*
        Convert a long n to a string s[].
        The length of s must be large enough to hold the result.
*/
void
convl2s (a, s)
long a;
register char *s;
{
        register char *d, *ss;
        register int sn;
        register unsigned long n;
        char temp [LONG_DIGITS];

        TICK("convl2s");

        /* Do the sign and handle 0x80000000 correctly */
        if (a >= 0) {
                sn = 0;
                n = (unsigned long) a;
        }
        else {
                sn = 1;
                n = (unsigned long) (-a);
        }

        /* put digits in reverse order into temp */
        d = &temp[0];
        *d++ = 0;
        if (n) while (n) {
                /* NOTE: in assembly, we would divide once */
                *d++ = (char)(n % 10) + '0';
                n = n / 10;
        }
        else {
                *d++ = '0';
        }

        /* insert the sign */
        if (sn) {
                *d++ = '-';
        }

        /* Reverse temp into s. */
        ss = s;
        while(*ss++ = *--d) {};

        TRACE("convl2s", printf("convl2s (%ld): %s\n", a, s));
}

/*
        Convert a long n to a string s[], minimum digit count c.
        The length of s must be large enough to hold any result.
*/
void
conul2sc(n, s, c)
register unsigned long n;
register char *s;
register int c;
{
        register char *d, *ss;
        char temp [LONG_DIGITS];

        TICK("conul2sc");

        /* put digits in reverse order into temp */
        d = &temp[0];
        *d++ = 0;
        while (n) {
                /* NOTE: in assembly, we would divide once */
                *d++ = (char)(n % 10) + '0';
                n /= 10;
                if (c > 0) {
                        c--;
                }
        }
        while (c > 0) {
                c--;
                *d++ = '0';
        }

        /* Reverse temp into s. */
        ss = s;
        while(*ss++ = *--d) {};

        TRACE("conul2sc", printf("conul2sc returns: %s\n", s));
}

/*
        Convert a long n to a hex string s[], minimum digit count c.
        The length of s must be large enough to hold any result.
*/
void
conl2h(n, s, c)
register unsigned long n;
register char *s;
register int c;
{
        register char *d, *ss;
        char temp [LONG_DIGITS];

        TICK("conl2h");

        /* put digits in reverse order into temp */
        d = &temp[0];
        *d++ = 0;
        while (n) {
                *d = ((char)n & 15) + '0';
                if (*d > '9') {
                        *d += 7;
                }
                d++;
                n >>= 4;
                if (c > 0) {
                        c--;
                }
        }
        while (c > 0) {
                c--;
                *d++ = '0';
        }

        /* Reverse temp into s. */
        ss = s;
        while(*ss++ = *--d) {};

        TRACE("conl2h", printf("conl2h returns: %s\n", s));
}

/*
        Skip blanks and tabs,  but not newlines.
*/
void
skip_bl()
{
        TICKB("skip_bl");

        while (ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f') {
                sysnext();
        }
        
        RETURN_VOID("skip_bl");
}

/*
        Skip characters up to but NOT including a newline.
*/
void
skip_1line()
{
        TICKB("skip_1line");

        while (ch != END_FILE && ch != '\n') {
                sysnext();
        }

        RETURN_VOID("skip_1line");
}

/*
        Skip characters up to and including a newline.
*/
void
skip_past()
{
        TICKB("skip_past");

        while (ch != END_FILE && ch != '\n') {
                sysnext();
        }

        if (ch == '\n') {
                sysnext();
                if (com_flag) {
                        sysnlput();
                }
                bump_line();
        }

        RETURN_VOID("skip_past");
}

/*
        Skip to the end of the current preprocessor directive.
        I.e., skip to the first newline not contained in a comment.
*/
void
skip_pp()
{
        TICKB("skip_pp");

        while (ch != '\n' && ch != END_FILE) {
                if (ch == '/') {
                        /* Possible comment. */
                        sysnext();
                        if (ch == '*') {
                                sysnext();
                                skip_comment();
                        }
                        else if (slc_flag && ch == '/') {
                                /* 8/1/89 Single-line comment */
                                while (ch != END_FILE && ch != '\n') {
                                        sysnext();
                                }
                                RETURN_VOID("skip_pp");
                        }
                        else {
                                syspushback(ch);
                                ch = '/';
                                RETURN_VOID("skip_pp");
                        }
                }
                else {
                        sysnext();
                }
        }
        RETURN_VOID("skip_pp");
}

/*
        Skip blanks, tabs, and comments.
        Also skip newlines if nl_flag is TRUE;
*/
void
skip_ws(nl_flag)
bool nl_flag;
{
        TRACEPB("skip_ws", printf("(%s)\n", pr_bool(nl_flag)));

        for(;;) {

                switch(ch) {

                case ' ':
                case '\t':
                case '\f':
                case '\v':
                        sysnext();
                        continue;

                case '\n':
                        if (nl_flag) {
                                bump_line();
                                sysnext();
                                continue;
                        }
                        else {
                                /* 3/3/89 */
                                goto done;
                        }

                case '/':
                        sysnext();
                        if (ch == '*') {
                                sysnext();
                                skip_comment();
                                continue;
                        }
                        else if (slc_flag && ch == '/') {
                                /* 8/1/89 Single-line comment */
                                while (ch != END_FILE && ch != '\n') {
                                        sysnext();
                                }
                                continue;
                        }
                        else {
                                syspushback(ch);
                                ch = '/';
                                goto done;
                        }

                default:
                        goto done;
                }
        }
done:
        RETURN_VOID("skip_ws");
}

/*
        Copy blanks, tabs and comments to the output.
        Also copy newlines if nl_flag is TRUE;
*/
void
copy_ws(nl_flag)
bool nl_flag;
{
        TRACEPB("copy_ws", printf("(%s)\n", pr_bool(nl_flag)));

        for(;;) {

                switch(ch) {

                case ' ':
                case '\t':
                case '\f':
                case '\v':
                        syscput(ch);
                        sysnext();
                        continue;

                case '\n':
                        if (nl_flag) {
                                bump_line();
                                sysnlput();
                                sysnext();
                                continue;
                        }
                        else {
                                /* 3/3/89 */
                                goto done;
                        }

                case '/':
                        sysnext();
                        if (ch == '*') {
                                sysnext();
                                syscput('/');
                                syscput('*');
                                copy_comment();
                                continue;
                        }
                        else if (slc_flag && ch == '/') {
                                /* 8/1/89 Single-line comment */
                                sysnext();
                                syscput('/');
                                syscput('/');
                                while (ch != END_FILE && ch != '\n') {
                                        syscput(ch);
                                        sysnext();
                                }
                                continue;
                        }
                        else {
                                syspushback(ch);
                                ch = '/';
                                goto done;
                        }

                default:
                        goto done;
                }
        }
done:
        RETURN_VOID("copy_ws");
}

/*
        Process a non-fatal error messages.
*/
void
error(message)
char *message;
{
        TICK("error");
        syscsts();
        t_errcount++;
        if (t_inlevel == 0) {
                printf("line %3d: %s\n", t_line, message);
        }
        else {
                printf("line %3d, %s: %s\n", t_line, t_file, message);
        }
}

void
err2(mess1, mess2)
char *mess1;
char *mess2;
{
        TICK("err2");
        syscsts();
        t_errcount++;
        if (t_inlevel == 0) {
                printf("line %3d: %s%s\n", t_line, mess1, mess2);
        }
        else {
                printf("line %3d, %s: %s%s\n", t_line, t_file, mess1, mess2);
        }
}

void
err3(mess1, mess2, mess3)
char *mess1;
char *mess2;
char *mess3;
{
        TICK("err3");
        syscsts();
        t_errcount++;
        if (t_inlevel == 0) {
                printf("line %3d: %s%s%s\n", t_line, mess1, mess2, mess3);
        }
        else {
                printf("line %3d, %s: %s%s%s\n",
                        t_line, t_file, mess1, mess2, mess3);
        }
}

/*
        Give an error message and exit.
*/
void
fatal(message)
char * message;
{
        printf("\nOh dear.  I can't go on like this...\n\n");
        printf("line %3d, %s: %s\n", t_line, t_file, message);

        TRACE("dump", m_stat());
        TRACE("dump", sl_dump());
        sysabort();
        
}

/*
        Internal error.
*/
void
syserr(message)
char *message;
{
        printf("\nOh dear.  There is something wrong with me...\n\n");
        printf("line %3d, %s: %s\n", t_line, t_file, message);

        TRACE("dump", m_stat());
        TRACE("dump", sl_dump());
        sysabort();
}

/*
        Process a non-fatal warning message.
*/
void
warning(message)
char *message;
{
        TICK("warning");
        syscsts();
        if (t_inlevel == 0) {
                printf("line %3d: (Warning) %s\n", t_line, message);
        }
        else {
                printf("line %3d, %s: (Warning) %s\n",
                        t_line, t_file, message);
        }
}

void
warn2(mess1, mess2)
char *mess1;
char *mess2;
{
        TICK("warn2");
        syscsts();
        if (t_inlevel == 0) {
                printf("line %3d: (Warning) %s%s\n", t_line, mess1, mess2);
        }
        else {
                printf("line %3d, %s: (Warning) %s%s\n",
                        t_line, t_file, mess1, mess2);
        }
}

void
warn3(mess1, mess2, mess3)
char *mess1;
char *mess2;
char *mess3;
{
        TICK("warn3");
        syscsts();
        if (t_inlevel == 0) {
                printf("line %3d: (Warning) %s%s%s\n",
                        t_line, mess1, mess2, mess3);
        }
        else {
                printf("line %3d, %s: (Warning) %s%s%s\n",
                        t_line, t_file, mess1, mess2, mess3);
        }
}