Logo Search packages:      
Sourcecode: vile version File versions

m4-filt.c

/*
 * $Header: /usr/build/vile/vile/filters/RCS/m4-filt.c,v 1.22 2003/05/24 00:49:25 tom Exp $
 *
 * Filter to add vile "attribution" sequences to selected bits of m4
 * input text.  This is in C rather than LEX because M4's quoting delimiters
 * change by embedded directives, to simplify inclusion of brackets.
 */

#include <filters.h>

DefineFilter("m4");

#define NAME_L_QUOTE "LeftQuote"
#define NAME_R_QUOTE "RightQuote"
#define NAME_L_CMT   "LeftComment"
#define NAME_R_CMT   "RightComment"

#define L_PAREN '('
#define R_PAREN ')'

#define L_QUOTE "`"
#define R_QUOTE "'"

#define L_CMT "#"
#define R_CMT "\n"

#define isIdent(c)  (isalpha(CharOf(c)) || (c) == '_')
#define isNamex(c)  (isalnum(CharOf(c)) || (c) == '_')

static char *Comment_attr;
static char *Error_attr;
static char *Ident_attr;
static char *Literal_attr;
static char *Number_attr;

/* changequote */
typedef struct {
    char *text;
    unsigned used, have;
} Quote;

typedef struct {
    char *name;
    void (*func) (char **);
} Funcs;

#define isQuote(s,n) (n.used && !strncmp(s, n.text, n.used))

#define write_quote(n) flt_puts(n.text, n.used, "")
#define wrong_quote(n) flt_puts(n.text, n.used, Error_attr)

static Quote leftquote, rightquote;
static Quote leftcmt, rightcmt;

static char *
SkipBlanks(char *src)
{
    while (isspace(CharOf(*src)))
      src++;
    return (src);
}

static void
new_quote(Quote * q, const char *s)
{
    q->used = strlen(s);
    q->text = do_alloc(q->text, q->used, &(q->have));
    strcpy(q->text, s);
}

static int
count_of(char **args)
{
    int count = 0;
    if (args != 0) {
      while (*args != 0) {
          args++;
          count++;
      }
    }
    return count;
}

static void
ChangeQuote(char **args)
{
    if (args != 0) {
      new_quote(&leftquote, count_of(args) > 0 ? args[0] : L_QUOTE);
      new_quote(&rightquote, count_of(args) > 1 ? args[1] : R_QUOTE);
    }
}

static void
ChangeComment(char **args)
{
    if (args != 0) {
      new_quote(&leftcmt, count_of(args) > 0 ? args[0] : L_CMT);
      new_quote(&rightcmt, count_of(args) > 1 ? args[1] : R_CMT);
    }
}

static char *
parse_arglist(char *name, char *s, char ***args, int *parens)
{
    char *r;
    char *v;
    int quoted;
    unsigned count;
    unsigned used;
    char *t;
    int processing;

    t = SkipBlanks(s);
    if (*parens == 0) {
      quoted = 0;
      count = 0;
      used = 0;
      if (*t == L_PAREN) {
          processing = 1;
          *args = type_alloc(char *, (char *) 0, sizeof(*args) *
                           (count + 4), &used);
          (*args)[count++] = strmalloc(name);
          (*args)[count] = 0;
          t++;
      } else {
          processing = 0;
      }
    } else {
      processing = 1;
      quoted = (*parens > 0);
      count = count_of(*args);
      used = sizeof(*args) * (count + 2); /* guess... */
    }

    if (processing) {
      for (;;) {
          r = t = SkipBlanks(t);
          while ((*t != ',') && (*t != R_PAREN) && *t)
            t++;
          if (*t == ',' || *t == R_PAREN) {
            v = (char *) malloc(1 + t - r);
            if (t != r)
                strncpy(v, r, t - r);
            v[t - r] = 0;
            *args = type_alloc(char *, (char *) (*args), sizeof(*args) *
                             (count + 2), &used);
            (*args)[count++] = v;
          }
          (*args)[count] = 0;
          if (isQuote(t, leftquote)) {
            t += leftquote.used;
            quoted = 1;
          } else if (isQuote(t, rightquote)) {
            t += rightquote.used;
            quoted = 0;
          } else if (*t == R_PAREN && !quoted) {
            t++;
            *parens = 0;
            break;
          } else if (!*t) {
            *parens = quoted ? 1 : -1;
            break;
          }
          t++;
      }
      flt_puts(s, t - s, "");
      return t;
    }
    return s;
}

static void
free_arglist(char **args)
{
    if (args != 0) {
      char **save = args;
      while (*args)
          free(*args++);
      free(save);
    }
}

static Funcs *
our_directive(char *name)
{
    static Funcs table[] =
    {
      {
          "changequote", ChangeQuote
      },
      {
          "changecom", ChangeComment
      },
    };
    Funcs *result = 0;
    size_t n;

    for (n = 0; n < sizeof(table) / sizeof(table[0]); n++) {
      if (!strcmp(name, table[n].name)) {
          result = table + n;
          break;
      }
    }
    return result;
}

static void
handle_directive(char ***args, int *parens)
{
    Funcs *ptr;

    if (*args != 0 && *parens == 0) {
      if ((ptr = our_directive((*args)[0])) != 0) {
          ptr->func(*args + 1);
      }
      free_arglist(*args);
      *parens = 0;
      *args = 0;
    }
}

/*
 * We really do not need to parse argument lists except for those that modify
 * the delimiters we'll use for subsequent parsing.
 */
static char *
parse_directive(char *name, char *s, char ***args, int *parens)
{
    if (our_directive(name) != 0) {
      s = parse_arglist(name, s, args, parens);
      handle_directive(args, parens);
    }
    return s;
}

static char *
extract_identifier(char *s, char ***args, int *parens)
{
    static char *name;
    static unsigned have;

    unsigned has_cpp = 0;
    unsigned need;
    char *attr;
    char *base;
    char *show = s;

    if (*s == '#') {
      has_cpp = 1;
      s++;
      s = SkipBlanks(s);
    }
    base = s;
    while (isNamex(*s))
      s++;
    if (base != s) {
      need = has_cpp + (s - base);
      name = do_alloc(name, need, &have);
      if (has_cpp) {
          name[0] = '#';
      }
      strncpy(name + has_cpp, base, s - base);
      name[(s - base) + has_cpp] = 0;
      if (!strcmp(name, "dnl")) {
          /* FIXME: GNU m4 may accept an argument list here */
          s += strlen(s);
          flt_puts(show, s - show, Comment_attr);
      } else if ((attr = keyword_attr(name)) != 0) {
          flt_puts(show, s - show, attr);
      } else {
          flt_puts(show, s - show, Ident_attr);
      }
      s = parse_directive(name, s, args, parens);
    }
    return s;
}

static int
has_endofcomment(char *s, int *level)
{
    char *base = s;
    while (*s) {
      if (isQuote(s, rightcmt)) {
          s += rightcmt.used;
          *level = 0;
          break;
      } else {
          ++s;
      }
    }
    return (s - base);
}

static int
has_endofliteral(char *s, int *level)
{
    char *base = s;
    while (*s) {
      if (isQuote(s, leftquote)) {
          s += leftquote.used;
          *level += 1;
      } else if (isQuote(s, rightquote)) {
          s += rightquote.used;
          *level -= 1;
          if (*level == 0)
            break;
      } else {
          ++s;
      }
    }
    return (s - base);
}

static char *
write_number(char *s)
{
    char *base = s;
    int radix = (*s == '0') ? ((s[1] == 'x' || s[1] == 'X') ? 16 : 8) : 10;
    int done = 0;

    if (radix == 16)
      s++;
    while (!done) {
      s++;
      switch (radix) {
      case 8:
          done = !isdigit(CharOf(*s)) || (*s == '8') || (*s == '9');
          break;
      case 10:
          done = !isdigit(CharOf(*s));
          break;
      case 16:
          done = !isxdigit(CharOf(*s));
          break;
      }
    }
    flt_puts(base, s - base, Number_attr);
    return s;
}

static char *
write_literal(char *s, int *literal)
{
    static char *buffer;
    static unsigned have;
    static unsigned used;

    unsigned c_length = has_endofliteral(s, literal);
    unsigned need = c_length;

    if (*literal == 0) {
      if (need > rightquote.used) {
          need -= rightquote.used;
          buffer = do_alloc(buffer, used + need + 1, &have);
          strncpy(buffer + used, s, need);
          used += need;
      }
      if (used) {
          flt_puts(buffer, used, Literal_attr);
          used = 0;
      }
      write_quote(rightquote);
    } else {
      buffer = do_alloc(buffer, used + need + 1, &have);
      strncpy(buffer + used, s, need);
      used += need;
    }
    return s + c_length;
}

static char *
write_comment(char *s, int *level)
{
    int c_length = has_endofcomment(s, level);
    flt_puts(s, c_length, Comment_attr);
    return s + c_length;
}

static void
init_filter(int before)
{
    if (before) {
      insert_keyword(NAME_L_QUOTE, L_QUOTE, 1);
      insert_keyword(NAME_R_QUOTE, R_QUOTE, 1);
      insert_keyword(NAME_L_CMT, L_CMT, 1);
      insert_keyword(NAME_R_CMT, R_CMT, 1);
    }
}

static void
do_filter(FILE *input GCC_UNUSED)
{
    static unsigned used;
    static char *line;

    char *s;
    char **args;
    int literal, comment, parens;

    new_quote(&leftquote, class_attr(NAME_L_QUOTE));
    new_quote(&rightquote, class_attr(NAME_R_QUOTE));
    new_quote(&leftcmt, class_attr(NAME_L_CMT));
    new_quote(&rightcmt, class_attr(NAME_R_CMT));

    Comment_attr = class_attr(NAME_COMMENT);
    Error_attr = class_attr(NAME_ERROR);
    Ident_attr = class_attr(NAME_IDENT);
    Literal_attr = class_attr(NAME_LITERAL);
    Number_attr = class_attr(NAME_NUMBER);

    args = 0;
    literal = 0;
    comment = 0;
    parens = 0;

    while (flt_gets(&line, &used) != NULL) {
      s = line;
      while (*s) {
          if (parens != 0) {
            s = parse_directive(args[0], s, &args, &parens);
          } else if (literal) {
            /*
             * Quoted literals can nest, and override comments
             */
            s = write_literal(s, &literal);
          } else if (isQuote(s, leftquote)) {
            write_quote(leftquote);
            s += leftquote.used;
            literal++;
            s = write_literal(s, &literal);
          } else if (isQuote(s, rightquote)) {
            wrong_quote(rightquote);
            s += rightquote.used;
            if (--literal > 0)
                s = write_literal(s, &literal);
            else
                literal = 0;
          } else if (comment) {
            /*
             * Comments don't nest
             */
            s = write_comment(s, &comment);
            comment = 0;
          } else if (isQuote(s, leftcmt)) {
            flt_puts(s, leftcmt.used, Comment_attr);
            s += leftcmt.used;
            comment = 1;
          } else if (isQuote(s, rightcmt)) {
            flt_puts(s, rightcmt.used, Comment_attr);
            s += rightcmt.used;
            comment = 0;
          } else if (isIdent(*s)) {
            s = extract_identifier(s, &args, &parens);
          } else if (isdigit(CharOf(*s))) {
            s = write_number(s);
          } else {
            flt_putc(*s++);
          }
      }
    }
}

Generated by  Doxygen 1.6.0   Back to index