]> git.sesse.net Git - rdpsrv/blobdiff - Xserver/lib/font/Type1/token.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / lib / font / Type1 / token.c
diff --git a/Xserver/lib/font/Type1/token.c b/Xserver/lib/font/Type1/token.c
new file mode 100644 (file)
index 0000000..da1c291
--- /dev/null
@@ -0,0 +1,1211 @@
+/* $XConsortium: token.c,v 1.3 94/02/04 17:07:17 gildea Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS.  THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE.  SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION.  IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* Authors: Sig Nin & Carol Thompson IBM Almaden Research Laboratory */
+#include "t1stdio.h"
+#include "util.h"
+#include "digit.h"
+#include "token.h"
+#include "tokst.h"
+#include "hdigit.h"
+/*
+ * -------------------------------------------------------------------
+ * Globals
+ * -------------------------------------------------------------------
+ */
+/* These variables are set by the caller */
+char           *tokenStartP;   /* Pointer to token buffer in VM */
+char           *tokenMaxP;     /* Pointer to last byte in buffer + 1 */
+/* These variables are set by TOKEN */
+int             tokenLength;   /* Characters in token */
+boolean         tokenTooLong;  /* Token too long for buffer */
+int             tokenType;     /* Type of token identified */
+psvalue         tokenValue;    /* Token value */
+/*
+ * -------------------------------------------------------------------
+ * Private variables
+ * -------------------------------------------------------------------
+ */
+static FILE    *inputFileP;    /* Current input file */
+/* Token */
+static char    *tokenCharP;    /* Pointer to next character in token */
+/*
+ * -------------------------------------------------------------------
+ * Private routines for manipulating numbers
+ * -------------------------------------------------------------------
+ */
+#define Exp10(e) \
+((e) == 0\
+ ? (double)(1.0)\
+ : (-64 <= (e) && (e) <= 63\
+    ? Exp10T[(e)+64]\
+    : P10(e)\
+   )\
+)
+static double Exp10T[128] = {
+  1e-64, 1e-63, 1e-62, 1e-61, 1e-60, 1e-59, 1e-58, 1e-57,
+  1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49,
+  1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41,
+  1e-40, 1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33,
+  1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25,
+  1e-24, 1e-23, 1e-22, 1e-21, 1e-20, 1e-19, 1e-18, 1e-17,
+  1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9,
+  1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
+  1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
+  1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
+  1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23,
+  1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31,
+  1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
+  1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47,
+  1e48, 1e49, 1e50, 1e51, 1e52, 1e53, 1e54, 1e55,
+  1e56, 1e57, 1e58, 1e59, 1e60, 1e61, 1e62, 1e63
+};
+static double P10(exponent)
+  long exponent;
+{
+  double value, power;
+  if (exponent < 0) {
+    power = 0.1;
+    value = (exponent & 1 ? power : 1.0);
+    exponent = -(++exponent >> 1); /* portable C for -(exponent/2) */
+  }
+  else {
+    power = 10.0;
+    value = (exponent & 1 ? power : 1.0);
+    exponent = exponent >> 1;
+  }
+  while(exponent > 0) {
+    power *= power;
+    if (exponent & 1)
+      value *= power;
+    exponent >>= 1;
+  }
+  return(value);
+}
+/*
+ * -------------------------------------------------------------------
+ * Private routines and macros for manipulating the input
+ * -------------------------------------------------------------------
+ */
+/* Get next character from the input --
+ *
+ */
+#define next_ch()    (getc(inputFileP))
+/* Push a character back into the input --
+ *
+ * Ungetc of EOF will fail, but that's ok: the next getc will
+ * return EOF.
+ *
+ * NOTE:  These macros are presently written to return the character
+ * pushed, or EOF if none was pushed.  However, they are not
+ * required to return anything in particular, and callers should
+ * not rely on the returned value.
+ */
+#define back_ch(ch)   (ungetc(ch, inputFileP))
+/* Push a character back into the input if it was not white space.
+ * If it is a carriage return (\r) then check next char for
+ * linefeed and consume them both, otherwise put next char back.
+ *
+ */
+#define back_ch_not_white(ch) \
+(\
+isWHITE_SPACE(ch)\
+ ? ((ch == '\r')\
+   ? (((ch = next_ch()) == '\n')\
+     ? EOF\
+     : back_ch(ch)\
+     )\
+   : EOF\
+   )\
+ : back_ch(ch)\
+)
+/*
+ * -------------------------------------------------------------------
+ * Private routines and macros for manipulating the token buffer
+ * -------------------------------------------------------------------
+ */
+/* Add a character to the token
+ * ---- use ONLY when you KNOW that this character will
+ *      be stored within the token buffer.
+ */
+#define save_unsafe_ch(ch) (*tokenCharP++ = ch)
+/* Add a character to the token, if not too long to fit */
+#define save_ch(ch) \
+((tokenCharP < tokenMaxP)\
+ ? save_unsafe_ch(ch)\
+ : (tokenTooLong = TRUE)\
+)
+
+#define save_ch_no_inc(ch) \
+((tokenCharP < tokenMaxP) && (*tokenCharP = ch))
+/*
+ * -------------------------------------------------------------------
+ * Action Routines
+ *
+ *  These routines all
+ *    -- take int ch as a parameter
+ *    -- return int ch if no token was recognized, DONE otherwise
+ *    -- leave the next character in the input, if returning DONE
+ * -------------------------------------------------------------------
+ */
+#define DONE  (256)
+/* Get the next input character */
+static int next_char(ch)
+  int ch;
+{
+  return(next_ch());
+}
+/* Add character to token */
+static int add_char(ch)
+  int ch;
+{
+  save_ch(ch);
+  return(next_ch());
+}
+/* -------------------------------------------------------------------
+ * Skip white space and comments
+ */
+/* Skip white space */
+static int skip_space(ch)
+  int ch;
+{
+  do {
+    ch = next_ch();
+  } while(isWHITE_SPACE(ch));
+  return(ch);
+}
+/* Skip comments */
+static int skip_comment(ch)
+  int ch;
+{
+  do {
+    ch = next_ch();
+  } while(isCOMMENT(ch));
+  return(ch);
+}
+/* -------------------------------------------------------------------
+ * Collect value elements for a number
+ */
+/* decimal integer or real number mantissa */
+static int m_sign;
+static long m_value;
+static long m_scale;
+/* real number exponent */
+static int e_sign;
+static long e_value;
+static long e_scale;
+/* radix number */
+static long r_base;
+static long r_value;
+static long r_scale;
+static int add_sign(ch)
+  int ch;
+{
+  m_sign = ch;
+  save_unsafe_ch(ch);
+  return(next_ch());
+}
+static int add_1st_digits(ch)
+  int ch;
+{
+  m_sign = '+';
+  return(add_digits(ch));
+}
+static int add_digits(ch)
+  int ch;
+{
+  long value, p_value, scale;
+  int digit;
+  /* On entry, expect m_sign to be set to '+' or '-';
+   *  ch is a decimal digit.
+   * Expect at most one character saved at this point,
+   *  a sign.  This routine will save up to 10 more
+   *  characters without checking the buffer boundary.
+   */
+  value = ch - '0';
+  save_unsafe_ch(ch);
+  ch = next_ch();
+  while(isDECIMAL_DIGIT(ch) && value < (MAX_INTEGER/10)) {
+    value = (value << 3) + (value << 1) + (ch - '0');
+    save_unsafe_ch(ch);
+    ch = next_ch();
+  }
+  /* Quick exit for small integers --
+   *    |x| <= 10*((MAX_INTEGER/10)-1)+9
+   *    |x| <= 2,147,483,639 for 32 bit integers
+   */
+  if (isNUMBER_ENDER(ch)) {
+    back_ch_not_white(ch);
+    tokenValue.integer = (m_sign == '-' ? -value : value);
+    tokenType = TOKEN_INTEGER;
+    return(DONE);
+  }
+  /* Handle additional digits.  Beyond the boundary case,
+   *   10*(MAX_INTEGER/10) <= |number| <= MAX_INTEGER
+   * just count the digits: the number is too large to
+   * represent as an integer and will be returned as a real.
+   * The mantissa of a real holds fewer bits than an integer.
+   */
+  p_value = value;
+  value = (m_sign == '-' ? -value : value);
+  scale = 0;
+  if (isDECIMAL_DIGIT(ch)) {
+    /* Handle the boundary case */
+    if (p_value == (MAX_INTEGER/10)) {
+      digit = ch - '0';
+      /* Must handle positive and negative values separately  */
+      /* for 2's complement arithmetic */
+      if (value > 0) {
+        if (digit <= MAX_INTEGER%10)
+          value = (value << 3) + (value << 1) + digit;
+        else
+          ++scale;  /* Too big, just count it */
+      }
+      else {
+        /* Use positive % operands for portability */
+        if (digit <= -(MIN_INTEGER+10)%10)
+          value = (value << 3) + (value << 1) - digit;
+        else
+          ++scale;  /* Too big, just count it */
+      }
+    }
+    else
+      ++scale;  /* Not boundary case, just count digit */
+    save_unsafe_ch(ch);
+    ch = next_ch();
+    /* Continue scanning digits, but can't store them */
+    while(isDECIMAL_DIGIT(ch)) {
+      ++scale;
+      save_ch(ch);
+      ch = next_ch();
+    }
+  }
+  /* Continue from here scanning radix integer or real */
+  m_value = value;
+  m_scale = scale;
+  /* Initialize for possible real */
+  e_sign = '+';
+  e_value = 0;
+  e_scale = 0;
+  return(ch);
+}
+static int add_1st_decpt(ch)
+  int ch;
+{
+  m_sign = '+';
+  return(add_decpt(ch));
+}
+static int add_decpt(ch)
+  int ch;
+{
+  /* On entry, expect m_sign to be set to '+' or '-' */
+  m_value = 0;
+  m_scale = 0;
+  save_unsafe_ch(ch);
+  return(next_ch());
+}
+static int add_fraction(ch)
+  int ch;
+{
+  long value, scale;
+  int digit;
+  /* On entry, expect m_value and m_scale to be initialized,
+   * and m_sign to be set to '+' or '-'.  Expect m_value and m_sign
+   * to be consistent (this is not checked).
+   */
+  value = m_value;
+  scale = m_scale;
+  /* Scan leading zeroes */
+  if (value == 0) {
+    while(ch == '0') {
+      --scale;
+      save_ch(ch);
+      ch = next_ch();
+    }
+    /* Scan first significant digit */
+    if (isDECIMAL_DIGIT(ch)) {
+      --scale;
+      value = ch - '0';
+      value = (m_sign == '-' ? -value : value);
+      save_ch(ch);
+      ch = next_ch();
+    }
+    else
+      /* no significant digits -- number is zero */
+      scale = 0;
+  }
+  /* value != 0 || value == 0 && !isDECIMAL_DIGIT(ch) */
+  /* Scan additional significant digits */
+  if (isDECIMAL_DIGIT(ch)) {
+    if (value > 0) {
+      while(isDECIMAL_DIGIT(ch) && value < (MAX_INTEGER/10)) {
+        --scale;
+        value = (value << 3) + (value << 1) + (ch - '0');
+        save_ch(ch);
+        ch = next_ch();
+      }
+      /* Check boundary case */
+      if (isDECIMAL_DIGIT(ch) && value == (MAX_INTEGER/10)) {
+        digit = ch - '0';
+        if (digit <= MAX_INTEGER%10) {
+          --scale;
+          value = (value << 3) + (value << 1) + digit;
+          save_ch(ch);
+          ch = next_ch();
+        }
+      }
+    }
+    else {
+      /* value < 0 */
+      while(isDECIMAL_DIGIT(ch) && value > -(-(MIN_INTEGER+10)/10+1)) {
+        /* Use positive / operands for portability */
+        --scale;
+        value = (value << 3) + (value << 1) - (ch - '0');
+        save_ch(ch);
+        ch = next_ch();
+      }
+      /* Check boundary case */
+      if (isDECIMAL_DIGIT(ch)
+          && value == -(-(MIN_INTEGER+10)/10+1)) {
+        digit = ch - '0';
+        if (digit <= -(MIN_INTEGER+10)%10) {
+        /* Use positive % operands for portability */
+          --scale;
+          value = (value << 3) + (value << 1) - digit;
+          save_ch(ch);
+          ch = next_ch();
+        }
+      }
+    }
+    /* Additional digits can be discarded */
+    while(isDECIMAL_DIGIT(ch)) {
+      save_ch(ch);
+      ch = next_ch();
+    }
+  }
+  /* Store results */
+  m_value = value;
+  m_scale = scale;
+  /* Initialize for possible real */
+  e_sign = '+';
+  e_value = 0;
+  e_scale = 0;
+  return(ch);
+}
+static int add_e_sign(ch)
+  int ch;
+{
+  e_sign = ch;
+  save_ch(ch);
+  return(next_ch());
+}
+static int add_exponent(ch)
+  int ch;
+{
+  long value, p_value;
+  long scale = 0;
+  int digit;
+  /* On entry, expect e_sign to be set to '+' or '-' */
+  value = ch - '0';
+  save_ch(ch);
+  ch = next_ch();
+  while(isDECIMAL_DIGIT(ch) && value < (MAX_INTEGER/10)) {
+    value = (value << 3) + (value << 1) + (ch - '0');
+    save_ch(ch);
+    ch = next_ch();
+  }
+  p_value = value;
+  value = (e_sign == '-' ? -value : value);
+  /* Handle additional digits.  Beyond the boundary case,
+   *   10*(MAX_INTEGER/10) <= |number| <= MAX_INTEGER
+   * just count the digits: the number is too large to
+   * represent as an integer.
+   */
+  if (isDECIMAL_DIGIT(ch)) {
+    /* Examine boundary case */
+    if (p_value == (MAX_INTEGER/10)) {
+      digit = ch - '0';
+      /* Must handle positive and negative values separately */
+      /*  for 2's complement arithmetic */
+      if (value > 0) {
+        if (digit <= MAX_INTEGER%10)
+          value = (value << 3) + (value << 1) + digit;
+        else
+          ++scale; /* Too big, just count it */
+      }
+      else {
+        /* Use positive % operands for portability */
+        if (digit <= -(MIN_INTEGER+10)%10)
+          value = (value << 3) + (value << 1) - digit;
+        else
+          ++scale; /* Too big, just count it */
+      }
+    }
+    else
+      ++scale;  /* Not boundary case, just count digit */
+    save_ch(ch);
+    ch = next_ch();
+    /* Continue scanning digits, but can't store any more */
+    while(isDECIMAL_DIGIT(ch)) {
+      ++scale;
+      save_ch(ch);
+      ch = next_ch();
+    }
+  }
+  /* Store results */
+  e_value = value;
+  e_scale = scale;
+  return(ch);
+}
+static int add_radix(ch)
+  int ch;
+{
+  if (2 <= m_value && m_value <= 36 && m_scale == 0) {
+    r_base = m_value;
+    save_ch(ch);
+    return(next_ch());
+  }
+  else {
+    /* Radix invalid, complete a name token */
+    return(AAH_NAME(ch));
+  }
+}
+static int add_r_digits(ch)
+  int ch;
+{
+  unsigned long value;
+  long radix, scale;
+  int digit;
+  /* NOTE:  The syntax of a radix number allows only for
+   * values of zero or more.  The value will be stored as
+   * a 32 bit integer, which PostScript then interprets
+   * as signed.  This means, for example, that the numbers:
+   *
+   *     8#37777777777
+   *    10#4294967295
+   *    16#FFFFFFFF
+   *    36#1Z141Z3
+   *
+   * are all interpreted as -1.  This routine implements this
+   * idea explicitly:  it accumulates the number's value
+   * as unsigned, then casts it to signed when done.
+   */
+  /* Expect r_base to be initialized */
+  radix = r_base;
+  value = 0;
+  scale = 0;
+  /* Scan leading zeroes */
+  while(ch == '0') {
+    save_ch(ch);
+    ch = next_ch();
+  }
+  /* Handle first non-zero digit */
+  if ((digit=digit_value[ch]) < radix) {
+    value = digit;
+    save_ch(ch);
+    ch = next_ch();
+    /* Add digits until boundary case reached */
+    while((digit=digit_value[ch]) < radix
+            && value < (MAX_ULONG / radix)) {
+      value = value * radix + digit;
+      save_ch(ch);
+      ch = next_ch();
+    };
+    /* Scan remaining digits */
+    if ((digit=digit_value[ch]) < radix) {
+      /* Examine boundary case ---
+       *   radix*(MAX_ULONG/radix) <= number <= MAX_ULONG
+       */
+      if (value == (MAX_ULONG/radix) && digit <= MAX_ULONG%radix)
+        value = value * radix + digit;
+      else
+        ++scale;
+      /* Continue scanning digits, but can't store them */
+      save_ch(ch);
+      ch = next_ch();
+      while(digit_value[ch] < radix) {
+        ++scale;
+        save_ch(ch);
+        ch = next_ch();
+      }
+    }
+  }
+  /* Store result */
+  r_value = (long) value; /* result is signed */
+  r_scale = scale;
+  return(ch);
+}
+/* -------------------------------------------------------------------
+ * Complete a number; set token type and done flag.
+ * Put current input character back, if it is not white space.
+ */
+/* Done: Radix Number */
+static int RADIX_NUMBER(ch)
+  int ch;
+{
+  back_ch_not_white(ch);
+  if (r_scale == 0) {
+    tokenValue.integer = r_value;
+    tokenType = TOKEN_INTEGER;
+  }
+  else {
+    tokenType = TOKEN_NAME;
+  }
+  return(DONE);
+}
+/* Done: Integer */
+static int INTEGER(ch)
+  int ch;
+{
+  back_ch_not_white(ch);
+  if (m_scale == 0) {
+    tokenValue.integer = m_value;
+    tokenType = TOKEN_INTEGER;
+  }
+  else {
+    tokenValue.real = (double)(m_value) * Exp10(m_scale);
+    tokenType = TOKEN_REAL;
+  }
+  return(DONE);
+}
+/* Done: Real */
+static int REAL(ch)
+  int ch;
+{
+  double temp;
+  back_ch_not_white(ch);
+  /* NOTE: ignore e_scale, since e_value alone will cause
+   *   exponent overflow if e_scale > 0.
+   */
+  /* HAZARD: exponent overflow of intermediate result
+   * (e.g., in 370 floating point); this should not be a problem
+   * with IEEE floating point.  Reduce exponent overflow hazard by
+   * combining m_scale and e_value first, if they have different signs,
+   * or multiplying m_value and one of the other factors, if both
+   * m_scale and e_value are negative.
+   */
+  if ((m_scale >= 0 && e_value <= 0)
+      || (m_scale <= 0 && e_value >= 0)) {
+    tokenValue.real = (double)(m_value) * Exp10(m_scale + e_value);
+  }
+  else {
+    temp = (double)(m_value) * Exp10(m_scale);
+    tokenValue.real = temp * Exp10(e_value);
+  }
+  tokenType = TOKEN_REAL;
+  return(DONE);
+}
+/* -------------------------------------------------------------------
+ * Assemble a hex string; set token type and done flag.
+ */
+/* Done: Hex String */
+static int HEX_STRING(ch)
+  int ch;
+{
+  int value;
+  while(TRUE) {
+    /* Process odd digit */
+    ch = next_ch();
+    if (!isHEX_DIGIT(ch)) {
+      /* Skip white space */
+      while(isWHITE_SPACE(ch))
+        ch = next_ch();
+      /* Check for terminator */
+      if (!isHEX_DIGIT(ch)) {
+        break;
+      }
+    }
+    value = digit_value[ch] << 4;
+    /* Process even digit */
+    ch = next_ch();
+    if (!isHEX_DIGIT(ch)) {
+      /* Skip white space */
+      while(isWHITE_SPACE(ch))
+        ch = next_ch();
+      /* Check for terminator */
+      if (!isHEX_DIGIT(ch)) {
+        save_ch(value);
+        break;
+      }
+    }
+    save_ch(value + digit_value[ch]);
+  }
+  /* Classify result, based on why loop ended */
+  if (ch == '>')
+    tokenType = TOKEN_HEX_STRING;
+  else {
+    /* save the invalid character for error reporting */
+    save_ch(ch);
+    tokenType = TOKEN_INVALID;
+  }
+  return(DONE);
+}
+/* -------------------------------------------------------------------
+ * Assemble a string; set token type and done flag
+ */
+/* Save a backslash-coded character in a string --
+ *
+ *   Store the proper character for special cases
+ *   "\b", "\f", "\n", "\r", and "\t".
+ *
+ *   Decode and store octal-coded character, up to
+ *   three octal digits, "\o", "\oo", and "\ooo".
+ *
+ *   The sequence "\<newline>" is a line continuation,
+ *   so consume both without storing anything.
+ *
+ *   The sequence "\<EOF>" is an error; exit without
+ *   storing anything and let the caller handle it.
+ *
+ *   For other characters, including the sequences
+ *   "\\", "\(", and "\)", simply store the second
+ *   character.
+ */
+static void save_digraph(ch)
+  int ch;
+{
+  int value;
+  switch (ch) {
+    case 'b':   /* backspace */
+      ch = '\b';
+      break;
+    case 'f':   /* formfeed */
+      ch = '\f';
+      break;
+    case 'n':   /* newline */
+      ch = '\n';
+      break;
+    case 'r':   /* carriage return */
+      ch = '\r';
+      break;
+    case 't':   /* horizontal tab */
+      ch = '\t';
+      break;
+    case '\n':  /* line continuation -- consume it */
+      return;
+    case '\r':  /* carriage return   -- consume it */
+      ch = next_ch();   /* look at next character, is it \n?  */
+      if (ch == '\n')  return;
+      back_ch(ch);      /* if not a line feed, then return it */
+      return;
+    case EOF:   /* end of file -- forget it */
+      return;
+  default:
+    /* scan up to three octal digits to get value */
+    if (isOCTAL_DIGIT(ch)) {
+      value = digit_value[ch];
+      ch = next_ch();
+      if (isOCTAL_DIGIT(ch)) {
+        value = (value << 3) + digit_value[ch];
+        ch = next_ch();
+        if (isOCTAL_DIGIT(ch))
+          value = (value << 3) + digit_value[ch];
+        else
+          back_ch(ch);
+      }
+      else
+        back_ch(ch);
+      ch = value;
+    }
+  }
+  /* Found a character to save */
+  save_ch(ch);
+}
+/* Done: String */
+static int STRING(ch)
+  int ch;
+{
+  int nest_level = 1;
+  tokenType = TOKEN_STRING;
+  do {
+    ch = next_ch();
+    while(!isSTRING_SPECIAL(ch)) {
+      save_ch(ch);
+      ch = next_ch();
+    };
+    switch (ch) {
+     case '(':
+       ++nest_level;
+       save_ch(ch);
+       break;
+     case ')':
+       if (--nest_level > 0)
+         save_ch(ch);
+       break;
+     case '\\':
+          save_digraph(next_ch());
+        break;
+     case '\r':
+        /* All carriage returns (\r) are turned into linefeeds (\n)*/
+          ch = next_ch();       /* get the next one, is it \n? */
+          if (ch != '\n') {     /* if not, then put it back.   */
+            back_ch(ch);
+          }
+          save_ch('\n');        /* in either case, save a linefeed */
+        break;
+     case EOF:
+       tokenType = TOKEN_INVALID;  /* Unterminated string */
+       nest_level = 0;
+       break;
+    }
+  } while(nest_level > 0);
+  /* If there's room, add a 0-byte termination without increasing string
+     length.  This fixes certain dependencies on 0-terminated strings */
+  save_ch_no_inc(0);
+
+  return(DONE);
+}
+/* -------------------------------------------------------------------
+ * Assemble a name; set token type and done flag.
+ * Put current input character back, if it is not white space.
+ */
+/* Done: Name
+ *  (Safe version used to complete name tokens that
+ *   start out looking like something else).
+ */
+static int AAH_NAME(ch)
+  int ch;
+{
+  do {
+    save_ch(ch);
+    ch = next_ch();
+  } while(isNAME(ch));
+  back_ch_not_white(ch);
+  tokenType = TOKEN_NAME;
+  return(DONE);
+}
+/* Done: Name */
+static int NAME(ch)
+  int ch;
+{
+  save_unsafe_ch(ch);
+  ch = next_ch();
+  if (isNAME(ch)) {
+    save_unsafe_ch(ch);
+    ch = next_ch();
+    if (isNAME(ch)) {
+      save_unsafe_ch(ch);
+      ch = next_ch();
+      if (isNAME(ch)) {
+        save_unsafe_ch(ch);
+        ch = next_ch();
+        if (isNAME(ch)) {
+          save_unsafe_ch(ch);
+          ch = next_ch();
+          if (isNAME(ch)) {
+            save_unsafe_ch(ch);
+            ch = next_ch();
+            if (isNAME(ch)) {
+              save_unsafe_ch(ch);
+              ch = next_ch();
+              while(isNAME(ch)) {
+                save_ch(ch);
+                ch = next_ch();
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  back_ch_not_white(ch);
+  tokenType = TOKEN_NAME;
+  return(DONE);
+}
+/* Done: Literal Name */
+static int LITERAL_NAME(ch)
+  int ch;
+{
+  if (isNAME(ch)) {
+    save_unsafe_ch(ch);
+    ch = next_ch();
+    if (isNAME(ch)) {
+      save_unsafe_ch(ch);
+      ch = next_ch();
+      if (isNAME(ch)) {
+        save_unsafe_ch(ch);
+        ch = next_ch();
+        if (isNAME(ch)) {
+          save_unsafe_ch(ch);
+          ch = next_ch();
+          if (isNAME(ch)) {
+            save_unsafe_ch(ch);
+            ch = next_ch();
+            if (isNAME(ch)) {
+              save_unsafe_ch(ch);
+              ch = next_ch();
+              while(isNAME(ch)) {
+                save_ch(ch);
+                ch = next_ch();
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  back_ch_not_white(ch);
+  tokenType = TOKEN_LITERAL_NAME;
+  return(DONE);
+}
+/* Done: immediate Name */
+static int IMMED_NAME(ch)
+  int ch;
+{
+  ch = next_ch();
+  if (isNAME(ch)) {
+    save_unsafe_ch(ch);
+    ch = next_ch();
+    if (isNAME(ch)) {
+      save_unsafe_ch(ch);
+      ch = next_ch();
+      if (isNAME(ch)) {
+        save_unsafe_ch(ch);
+        ch = next_ch();
+        if (isNAME(ch)) {
+          save_unsafe_ch(ch);
+          ch = next_ch();
+          if (isNAME(ch)) {
+            save_unsafe_ch(ch);
+            ch = next_ch();
+            if (isNAME(ch)) {
+              save_unsafe_ch(ch);
+              ch = next_ch();
+              while(isNAME(ch)) {
+                save_ch(ch);
+                ch = next_ch();
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  back_ch_not_white(ch);
+  tokenType = TOKEN_IMMED_NAME;
+  return(DONE);
+}
+/* Done: Name found while looking for something else */
+static int OOPS_NAME(ch)
+  int ch;
+{
+  back_ch_not_white(ch);
+  tokenType = TOKEN_NAME;
+  return(DONE);
+}
+/* -------------------------------------------------------------------
+ * Complete a miscellaneous token; set token type and done flag.
+ */
+/* Done: Unmatched Right Angle-Bracket */
+static int RIGHT_ANGLE(ch)
+  int ch;
+{
+  tokenType = TOKEN_RIGHT_ANGLE;
+  return(DONE);
+}
+/* Done: Unmatched Right Parenthesis */
+static int RIGHT_PAREN(ch)
+  int ch;
+{
+  tokenType = TOKEN_RIGHT_PAREN;
+  return(DONE);
+}
+/* Done: Left Brace */
+static int LEFT_BRACE(ch)
+  int ch;
+{
+  tokenType = TOKEN_LEFT_BRACE;
+  return(DONE);
+}
+/* Done: Right Brace */
+static int RIGHT_BRACE(ch)
+  int ch;
+{
+  tokenType = TOKEN_RIGHT_BRACE;
+  return(DONE);
+}
+/* Done: Left Bracket */
+static int LEFT_BRACKET(ch)
+  int ch;
+{
+  save_unsafe_ch(ch);
+  tokenType = TOKEN_LEFT_BRACKET;
+  return(DONE);
+}
+/* Done: Right Bracket */
+static int RIGHT_BRACKET(ch)
+  int ch;
+{
+  save_unsafe_ch(ch);
+  tokenType = TOKEN_RIGHT_BRACKET;
+  return(DONE);
+}
+/* Done: Break */
+static int BREAK_SIGNAL(ch)
+  int ch;
+{
+  tokenType = TOKEN_BREAK;
+  return(DONE);
+}
+/* Done: No Token Found */
+static int NO_TOKEN(ch)
+  int ch;
+{
+  tokenType = TOKEN_EOF;
+  return(DONE);
+}
+/*
+ * -------------------------------------------------------------------
+ *  scan_token -- scan one token from the input.  It uses a simple
+ *    finite state machine to recognize token classes.
+ *
+ *  The input is from a file.
+ *
+ *  On entry --
+ *
+ *    inputP -> input PostScript object, a file.
+ *    tokenStartP -> buffer in VM for accumulating the token.
+ *    tokenMaxP -> last character in the token buffer
+ *
+ *  On exit --
+ *
+ *    tokenLength = number of characters in the token
+ *    tokenTooLong = TRUE if the token did not fit in the buffer
+ *    tokenType = code for the type of token parsed.
+ *    tokenValue = converted value of a numeric token.
+ *
+ *
+ * -------------------------------------------------------------------
+ */
+void scan_token(inputP)
+  psobj *inputP;
+{
+  int ch;
+  unsigned char *stateP = s0;
+  unsigned char entry;
+  int (*actionP)();
+  /* Define input source */
+  inputFileP = inputP->data.fileP;
+  if (inputFileP == NULL)  {
+    tokenType = TOKEN_EOF;
+    return;
+  }
+  /* Ensure enough space for most cases
+   * (so we don't have to keep checking)
+   * The length needs to cover the maximum number
+   * of save_unsafe_ch() calls that might be executed.
+   * That number is 11 (a sign and 10 decimal digits, e.g.,
+   * when scanning -2147483648), but use MAX_NAME_LEN
+   * in case someone changes that without checking.
+   */
+  tokenStartP = vm_next_byte();
+  tokenMaxP = tokenStartP + MIN(vm_free_bytes(), MAX_STRING_LEN);
+  if ((tokenMaxP-tokenStartP) < (MAX_NAME_LEN)) {
+    tokenLength = 0;
+    tokenTooLong = TRUE;
+    tokenType = TOKEN_NONE;
+    tokenValue.integer = 0;
+    return;
+  }
+  /* Reset token */
+  tokenCharP = tokenStartP;
+  tokenTooLong = FALSE;
+  /* Scan one token */
+  ch = next_ch();
+  do {
+    entry = stateP[ch];
+    stateP = classActionTable[entry].nextStateP;
+    actionP = classActionTable[entry].actionRoutineP;
+    ch = (*actionP)(ch);
+  } while(ch != DONE);
+  /* Return results */
+  tokenLength = tokenCharP - tokenStartP;
+}