Logo Search packages:      
Sourcecode: a2ps version File versions

sshread.c

/*
 * sshread.c
 *
 * routines of input, and formatting according to the styles
 * Copyright (c) 1988, 89, 90, 91, 92, 93 Miguel Santana
 * Copyright (c) 1995, 96, 97, 98 Akim Demaille, Miguel Santana
 * $Id: sshread.c,v 1.63 1998/03/04 16:20:59 demaille Exp $
 */

/*
 * This file is part of a2ps.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * $Id: sshread.c,v 1.63 1998/03/04 16:20:59 demaille Exp $
 */

#include "a2ps.h"
#include "sshread.h"
#include "ssheet.h"
#include "routines.h"
#include "buffer.h"
#include "jobs.h"
#include "fjobs.h"
#include "psgen.h"
#include "assert.h"
#include "quotearg.h"

/*
 * Use the information offered by main.c
 */
extern struct a2ps_job *job;

/*
 * Shortcut to call regex upon a buffer, and store in a token
 */
#define buffer_match(buffer,regex,token)              \
   re_match (regex,                                   \
           (char *) buffer->value, buffer->len, buffer->curr,     \
           token->registers)

/*
 * Structure in which is stored the result of a parsing
 */
struct token
  {
    struct re_registers *registers;
    struct darray *rhs;
  };

#define token_dest(_i_) \
    ((struct faced_string *) token->rhs->content[_i_])

#define token_dest_fface(_i_) \
    (token_dest(_i_)->face)

#define token_dest_face(_i_)  \
    (fface_get_face(token_dest_fface(_i_)))

#define token_dest_fflags(_i_)      \
    (fface_get_flags(token_dest_fface(_i_)))

static inline struct token *
token_new (void)
{
  struct token *res = XMALLOC (struct token, 1);
  res->registers = XMALLOC (struct re_registers, 1);
  res->registers->start = XMALLOC (regoff_t, 30);
  res->registers->end = XMALLOC (regoff_t, 30);
  return res;
}

static inline struct darray *
rhs_plain_new (void)
{
  return rhs_new_single (NULL, 0, Plain_fface);
}

static inline void
token_free (struct token *token)
{
  free (token);
}

/* Where the token and its attributes are stored */
static struct token *token = NULL;
#define token_set_registers(_start_, _len_)           \
 do {                                     \
  token->registers->start [0] = _start_;        \
  token->registers->end [0] = _start_ + _len_;        \
 } while (0)

#define token_start(_i_)            \
  token->registers->start [token_dest(_i_)->reg_ref]

#define token_end(_i_)        \
  token->registers->end [token_dest(_i_)->reg_ref]

static struct darray *plain_rhs = NULL;

/****************************************************************/
/*              pretty printing service routines                */
/****************************************************************/
/*
 * Eat characters as long as their in the 2nd alphabet
 * and we are in the buffer.
 */
static inline void
match_word (buffer_t * buffer, struct style_sheet *sheet)
{
  int start = buffer->curr;

  do
    buffer->curr++;
  while (sheet->alpha2[*(buffer->content + buffer->curr)]
       && !buffer_is_empty (buffer));

  token->rhs = plain_rhs;
  token_dest (0)->face = Plain_fface;
  token->registers->start[0] = start;
  token->registers->end[0] = buffer->curr;
}

/****************************************************************/
/*                      lexical analysis routines               */
/****************************************************************/
#define word_regexp(_i_)      \
   (((struct rule *) words->regexps->content[_i_]))
/*
 * Return true if there is a element of WORDS which keywords-match
 * current point of BUFFER.  Fill TOKEN with the matching part.
 */
static inline int
match_keyword (buffer_t * buffer,
             struct words *words,
             uchar * alphabet)
{
  struct rule **key;
  uchar *string = buffer->value + buffer->curr;
  int i;
  int res;

  /* First try the words */
  if (words->min[*string])
    for (key = words->max[*string]
       ; words->min[*string] <= key
       ; key--)
      {
      if (ustrprefix ((*key)->word, string)
          && !alphabet[string[ustrlen ((*key)->word)]])
        {
          token->rhs = (*key)->rhs;
          token_set_registers (buffer->curr, ustrlen ((*key)->word));
          buffer->curr += ustrlen ((*key)->word);
          return 1;
        }
      }

  /* Then the regexps, in reversed order (in order to take the
   * _last_ definition */
  for (i = (int) words->regexps->len - 1; i >= 0; i--)
    {
      res = buffer_match (buffer, word_regexp (i)->regex, token);
      switch (res)
      {
      case -2:
        fprintf (stderr, "An error occured while matching\n");
        break;
      case -1:
        continue;
      default:
        token->rhs = word_regexp (i)->rhs;
        buffer->curr += res;
        return 1;
      }
    }

  /* Report that nothing matches */
  return 0;
}

/*
 * Return true if there is a element of WORDS which operators-match
 * current point of BUFFER.  Fill TOKEN with the matching part.
 */
static inline int
match_operator (buffer_t * buffer,
            struct words *words)
{
  struct rule **key;
  uchar *string = buffer->value + buffer->curr;
  int i;
  int res;

  /* First the words */
  if (words->min[*string])
    for (key = words->max[*string]
       ; words->min[*string] <= key
       ; key--)
      {
      if (ustrprefix ((*key)->word, string))
        {
          token->rhs = (*key)->rhs;
          token_set_registers (buffer->curr, ustrlen ((*key)->word));
          buffer->curr += ustrlen ((*key)->word);
          return 1;
        }
      }

  /* Then the regexps, in reversed order (in order to take the
   * _last_ definition */
  for (i = (int) words->regexps->len - 1; i >= 0; i--)
    {
      res = buffer_match (buffer, word_regexp (i)->regex, token);
      switch (res)
      {
      case -2:
        fprintf (stderr, "An error occured while matching\n");
        break;
      case -1:
        continue;
      default:
        token->rhs = word_regexp (i)->rhs;
        buffer->curr += res;
        return 1;
      }
    }

  /* Report failure */
  return 0;
}

/*
 * If buffer+*curr begins with a sequence, return that sequence.
 * Otherwise NULL
 */
#ifdef SEQ
#undef SEQ
#endif
#define SEQ(_i_)  \
   ((struct sequence *) sheet->sequences->content [i])
static inline struct sequence *
match_sequence (buffer_t * buffer, struct style_sheet *sheet)
{
  int i;
  int res;
  uchar *string = buffer->value + buffer->curr;

  /* In reversed order (in order to take the _last_ definition */
  for (i = (int) sheet->sequences->len - 1; i >= 0; i--)
    {
      if (SEQ (i)->open->regex)
      {
        /* The regexp patterns */
        res = buffer_match (buffer, SEQ (i)->open->regex, token);
        switch (res)
          {
          case -2:
            fprintf (stderr, "An error occured while matching\n");
            break;
          case -1:
            continue;
          default:
            token->rhs = SEQ (i)->open->rhs;
            buffer->curr += res;
            return SEQ (i);
          }
      }
      else
      {
        /* It's a string */
        if (ustrprefix (SEQ (i)->open->word, string))
          {
            token_set_registers (buffer->curr, ustrlen (SEQ (i)->open->word));
            token->rhs = SEQ (i)->open->rhs;
            buffer->curr += ustrlen (SEQ (i)->open->word);
            return SEQ (i);
          }
      }
    }
  return NULL;
}

/*
 * Put in token the token recognized.
 * The number of token read, 0 if nothing left
 */
static inline int
ssh_get_token (buffer_t * buffer, struct style_sheet *sheet)
{
  static int return_to_plain = false;
  /* NULL if not in a sequence currently */
  static struct sequence *sequence = NULL;

  if (buffer_is_empty (buffer))
    {
      buffer_get (buffer);

      /* We don't trust liba2ps for the line numbers, because
       * if a2ps skips some lines (e.g., --strip-level, or INVISIBLE),
       * liba2ps will number upon output lines, not imput lines,
       * which is what is expected */
      (CURRENT_FILE (job))->lines = buffer->line;

      if (buffer->len == 0)
      {
        /* end of file: reset values */
        /* If this is a new file, it must not depend on the trailling
         * parameters of the previous file */
        sequence = NULL;
        return_to_plain = false;
        return 0;
      }
    }

  if (return_to_plain)
    {
      return_to_plain = false;
      token->rhs = plain_rhs;
      token_dest (0)->face = Plain_fface;
    }

  if (sequence)
    {
      /* escape: not converted when in a sequence */
      if (match_operator (buffer, sequence->exceptions))
      return 1;
      /* end of sequence ? */
      if (match_operator (buffer, sequence->close))
      {
        return_to_plain = true;
        sequence = NULL;
        return 1;
      }
      /* We are in a sequence not to be closed yet.
       * Advance of 1 char */
      token->rhs = plain_rhs;
      token_dest (0)->face = sequence->face;
      token->registers->start[0] = buffer->curr++;
      token->registers->end[0] = buffer->curr;
      return 1;
    }
  else
    {                   /* (not in sequence) */
      if ((sequence = match_sequence (buffer, sheet)))
      return 1;
      else if (sheet->alpha1[buffer->content[buffer->curr]])
      {
        /* we are in a word since this was a char belonging to the
         * first alphabet */
        if (match_keyword (buffer, sheet->keywords, sheet->alpha2)
            || match_operator (buffer, sheet->operators))
          {
            return_to_plain = true;
            return 1;
          }
        else
          {
            /* since some characters may be used inside an identifier
             * (eg, x' = x in claire) but can also be used to open
             * a special sequence (eg, 'x' in claire), then we must read
             * the whole word, and print in.
             */
            match_word (buffer, sheet);
            return 1;
          }
      }
      else if (match_operator (buffer, sheet->operators))
      {
        return_to_plain = true;
        return 1;
      }
    }

  /* We did not recognize something special */
  token->rhs = plain_rhs;
  token->registers->start[0] = buffer->curr++;
  token->registers->end[0] = buffer->curr;
  return 1;
}

#define GRAB_TAG(_tag_)                         \
  do {                                          \
    ustrncat (_tag_,                            \
            buffer->content + token_start (i),  \
            token_end (i) - token_start (i));         \
  } while (0)

/*
 * ssh-Pretty print a file to postscript
 */
void
ssh_print_postscript (struct a2ps_job *Job,
                  buffer_t * buffer,
                  struct style_sheet *sheet)
{
  struct fface_s fface;
  /* To grab the encoding switching instruction */
  uchar bufenc[512];
  int grabbing_encoding = false;
  size_t i;

  *bufenc = '\0';
  fface = Plain_fface;

  /* I must do this because of the broken handling of the registers in
   * regex.  Until I find a way to ensure enough place in the
   * registers, without having to trust regex. */
  if (!token)
    {
      token = token_new ();
      plain_rhs = rhs_plain_new ();
    }

  while (ssh_get_token (buffer, sheet) != 0)
    for (i = 0; i < token->rhs->len; i++)
      {
      /* Is a new face ? */
      if (!fface_squ (fface, token_dest_fface (i)))
        {
          /* Reset dynamic markers */
          if (token_dest_fflags (i) & ff_Tag1)
            *Job->tag1 = '\0';
          if (token_dest_fflags (i) & ff_Tag2)
            *Job->tag2 = '\0';
          if (token_dest_fflags (i) & ff_Tag3)
            *Job->tag3 = '\0';
          if (token_dest_fflags (i) & ff_Tag4)
            *Job->tag4 = '\0';
          if (grabbing_encoding
            && (!(token_dest_fflags (i) & ff_Encoding)))
            {
            /* Grabbing of the encoding name is completed */
            struct encoding *newenc;
            newenc = get_encoding_by_alias (job, (char *) bufenc);
/*          encoding_build_faces_wx (job, newenc); */
            if (!newenc)
              error (0, 0, _ ("unknown encoding `%s', ignored"),
                   quotearg ((char *) bufenc));
            else
              ps_switch_encoding (Job, newenc);
            *bufenc = '\0';
            grabbing_encoding = false;
            }
          fface = token_dest (i)->face;
        }

      /* See if there are some information to grab */
      if (token_dest (i)->string)
        {
          if (fface_get_flags (fface) & ff_Tag1)
            ustrcat (Job->tag1, token_dest (i)->string);
          if (fface_get_flags (fface) & ff_Tag2)
            ustrcat (Job->tag2, token_dest (i)->string);
          if (fface_get_flags (fface) & ff_Tag3)
            ustrcat (Job->tag3, token_dest (i)->string);
          if (fface_get_flags (fface) & ff_Tag4)
            ustrcat (Job->tag4, token_dest (i)->string);
          /* Grab the dynamic encodings */
          if (fface_get_flags (fface) & ff_Encoding)
            {
            grabbing_encoding = true;
            ustrcat (bufenc, token_dest (i)->string);
            }
        }
      else
        {
          if (fface_get_flags (fface) & ff_Tag1)
            GRAB_TAG (Job->tag1);
          if (fface_get_flags (fface) & ff_Tag2)
            GRAB_TAG (Job->tag2);
          if (fface_get_flags (fface) & ff_Tag3)
            GRAB_TAG (Job->tag3);
          if (fface_get_flags (fface) & ff_Tag4)
            GRAB_TAG (Job->tag4);
          /* Grab the dynamic encodings */
          if (fface_get_flags (fface) & ff_Encoding)
            {
            grabbing_encoding = true;
            GRAB_TAG (bufenc);
            }
        }

      /*
       * If not invisible, give it to liba2ps for printing.
       */
      if (!(fface_get_flags (fface) & ff_Invisible))
        {
          if (token_dest (i)->string)
            ps_print_string (Job, token_dest (i)->string,
                         fface.face);
          else
            ps_print_buffer (Job, buffer->content,
                         token_start (i), token_end (i),
                         fface.face);
        }
      }

  /* FIXME: Find a way to remove the token some day
     token_free (token);
   */
}

Generated by  Doxygen 1.6.0   Back to index