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

/*      Copyright (c) 1984, 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 "e.h"
#include "e.def"
#include <locale.h>

#define SSIZE   400
char    token[SSIZE];
int     sp;
#define putbak(c)       *ip++ = c;
#define PUSHBACK        300     /* maximum pushback characters */
char    ibuf[PUSHBACK+SSIZE];   /* pushback buffer for definitions, etc. */
char    *ip     = ibuf;

extern tbl *keytbl[];
extern tbl *deftbl[];

void define(int);
void delim(void);
void getstr(char *, int);
void include(void);
int openinfile(void);
void pbstr(char *);
void space(void);

int
gtc(void)
{
loop:
        if (ip > ibuf)
                return (*--ip); /* already present */
        lastchar = getc(curfile);
        if (lastchar == '\n')
                linect++;
        if (lastchar != EOF)
                return (lastchar);
        if (++ifile > svargc) {
                return (EOF);
        }
        (void) fclose(curfile);
        linect = 1;
        if (openinfile() == 0)
                goto loop;
        return (EOF);
}
/*
 *      open file indexed by ifile in svargv, return non zero if fail
 */
int
openinfile(void)
{
        if (strcmp(svargv[ifile], "-") == 0) {
                curfile = stdin;
                return (0);
        } else if ((curfile = fopen(svargv[ifile], "r")) != NULL) {
                return (0);
        }
        error(FATAL, gettext("can't open file %s"), svargv[ifile]);
        return (1);
}

void
pbstr(char *str)
{
        char *p;

        p = str;
        while (*p++)
                ;
        --p;
        if (ip >= &ibuf[PUSHBACK])
                error(FATAL, gettext("pushback overflow"));
        while (p > str)
                putbak(*--p);
}

int
yylex(void)
{
        int c;
        tbl *tp, *lookup();

beg:
        while ((c = gtc()) == ' ' || c == '\n')
                ;
        yylval = c;
        switch (c) {

        case EOF:
                return (EOF);
        case '~':
                return (SPACE);
        case '^':
                return (THIN);
        case '\t':
                return (TAB);
        case '{':
                return ('{');
        case '}':
                return ('}');
        case '"':
                for (sp = 0; (c = gtc()) != '"' && c != '\n'; ) {
                        if (c == '\\')
                                if ((c = gtc()) != '"')
                                        token[sp++] = '\\';
                        token[sp++] = c;
                        if (sp >= SSIZE)
                                error(FATAL, gettext(
                                    "quoted string %.20s... too long"), token);
                }
                token[sp] = '\0';
                yylval = (int)&token[0];
                if (c == '\n')
                        error(!FATAL, gettext("missing \" in %.20s"), token);
                return (QTEXT);
        }
        if (c == righteq)
                return (EOF);

        putbak(c);
        getstr(token, SSIZE);
        if (dbg) printf(".\tlex token = |%s|\n", token);
        if ((tp = lookup(deftbl, token, NULL)) != NULL) {
                putbak(' ');
                pbstr(tp->defn);
                putbak(' ');
                if (dbg)
                        printf(".\tfound %s|=%s|\n", token, tp->defn);
        } else if ((tp = lookup(keytbl, token, NULL)) == NULL) {
                if (dbg) printf(".\t%s is not a keyword\n", token);
                return (CONTIG);
        } else if (tp->defn == (char *)DEFINE ||
            tp->defn == (char *)NDEFINE || tp->defn == (char *)TDEFINE)
                define((int)tp->defn);
        else if (tp->defn == (char *)DELIM)
                delim();
        else if (tp->defn == (char *)GSIZE)
                globsize();
        else if (tp->defn == (char *)GFONT)
                globfont();
        else if (tp->defn == (char *)INCLUDE)
                include();
        else if (tp->defn == (char *)SPACE)
                space();
        else {
                return ((int)tp->defn);
        }
        goto beg;
}

void
getstr(char *s, int n)
{
        int c;
        char *p;

        p = s;
        while ((c = gtc()) == ' ' || c == '\n')
                ;
        if (c == EOF) {
                *s = 0;
                return;
        }
        while (c != ' ' && c != '\t' && c != '\n' && c != '{' && c != '}' &&
            c != '"' && c != '~' && c != '^' && c != righteq) {
                if (c == '\\')
                        if ((c = gtc()) != '"')
                                *p++ = '\\';
                *p++ = c;
                if (--n <= 0)
                        error(FATAL, gettext("token %.20s... too long"), s);
                c = gtc();
        }
        if (c == '{' || c == '}' || c == '"' || c == '~' || c == '^' ||
            c == '\t' || c == righteq)
                putbak(c);
        *p = '\0';
        yylval = (int)s;
}

int
cstr(char *s, int quote, int maxs)
{
        int del, c, i;

        s[0] = 0;
        while ((del = gtc()) == ' ' || del == '\t')
                ;
        if (quote) {
                for (i = 0; (c = gtc()) != del && c != EOF; ) {
                        s[i++] = c;
                        if (i >= maxs)
                                return (1);     /* disaster */
                }
        } else {
                if (del == '\n')
                        return (1);
                s[0] = del;
                for (i = 1; (c = gtc()) != ' ' && c != '\t' &&
                    c != '\n' && c != EOF; /* empty */) {
                        s[i++] = c;
                        if (i >= maxs)
                                return (1);     /* disaster */
                }
        }
        s[i] = '\0';
        if (c == EOF)
                error(FATAL, gettext("Unexpected end of input at %.20s"), s);
        return (0);
}

void
define(int type)
{
        char *strsave(), *p1, *p2;
        tbl *lookup();

        getstr(token, SSIZE);   /* get name */
        if (type != DEFINE) {
                (void) cstr(token, 1, SSIZE);   /* skip the definition too */
                return;
        }
        p1 = strsave(token);
        if (cstr(token, 1, SSIZE))
                error(FATAL, gettext(
                    "Unterminated definition at %.20s"), token);
        p2 = strsave(token);
        lookup(deftbl, p1, p2);
        if (dbg) printf(".\tname %s defined as %s\n", p1, p2);
}

char    *spaceval   = NULL;

void
space(void) /* collect line of form "space amt" to replace \x in output */
{
        char *strsave();

        getstr(token, SSIZE);
        spaceval = strsave(token);
        if (dbg) printf(".\tsetting space to %s\n", token);
}


char *
strsave(char *s)
{
        char *malloc();
        char *q;

        q = malloc(strlen(s)+1);
        if (q == NULL)
                error(FATAL, gettext("out of space in strsave on %s"), s);
        strcpy(q, s);
        return (q);
}

void
include(void)
{
        error(!FATAL, gettext("Include not yet implemented"));
}

void
delim(void)
{
        yyval = eqnreg = 0;
        if (cstr(token, 0, SSIZE))
                error(FATAL, gettext("Bizarre delimiters at %.20s"), token);
        lefteq = token[0];
        righteq = token[1];
        if (lefteq == 'o' && righteq == 'f')
                lefteq = righteq = '\0';
}