DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T i

⟦dd04c699b⟧ TextFile

    Length: 15883 (0x3e0b)
    Types: TextFile
    Names: »iscan.c«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦ff23ba0e6⟧ »./ghostscript-1.3.tar.Z« 
        └─⟦a24a58cd3⟧ 
            └─⟦this⟧ »iscan.c« 

TextFile

/* Copyright (C) 1989 Aladdin Enterprises.  All rights reserved.
   Distributed by Free Software Foundation, Inc.

This file is part of Ghostscript.

Ghostscript is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
to anyone for the consequences of using it or for whether it serves any
particular purpose or works at all, unless he says so in writing.  Refer
to the Ghostscript General Public License for full details.

Everyone is granted permission to copy, modify and redistribute
Ghostscript, but only under the conditions described in the Ghostscript
General Public License.  A copy of this license is supposed to have been
given to you along with Ghostscript so you can know your rights and
responsibilities.  It should be in a file named COPYING.  Among other
things, the copyright notice and this notice must be preserved on all
copies.  */

/* iscan.c */
/* Token scanner for GhostScript interpreter */
#include <stdio.h>			/* for stream.h */
#include <ctype.h>
#include "ghost.h"
#include "alloc.h"
#include "dict.h"			/* for //name lookup */
#include "errors.h"
#include "store.h"
#include "stream.h"

/* Array packing flag */
int array_packing;

/* Forward references */
private	int	scan_hex_string(P3(stream *, ref *, byte *(*)())),
		scan_int(P4(register stream *, int, ulong *, double *)),
		scan_name(P3(stream *, int, ref *)),
		scan_string(P4(stream *, int, ref *, byte *(*)()));

/* Import the dictionary stack for //name lookup */
extern ref *dsp;

/* Static constants */
private ref left_bracket;
private ref right_bracket;

/* An array for fast scanning of names and hex strings. */
/*  Indexed by character code (including EOFC), it contains: */
/*	0 - 15 for valid hex digits, */
/*	ctype_name for other characters valid in names, */
/*	ctype_space for whitespace characters, */
/*	ctype_eof for end-of-file, and */
/*	ctype_other for everything else. */
private char scan_char_array[257];
char *scan_char_decoder = &scan_char_array[1];	/* account for EOFC */
#define ctype_name 0x10
#define ctype_space 0x11
#define ctype_other 0x12
#define ctype_eof 0x13

/* Type definition for alloc_shrink and alloc_shrink_copy */
typedef byte *(*alloc_end_proc)(P4(byte *, uint, uint, char *));

/* A structure for dynamically growable objects */
typedef struct dynamic_area_s {
	byte *base;
	byte *next;
	uint size;
	byte *limit;
} dynamic_area;

/* Begin a dynamic object */
/* Note that alloc_dynamic may return 0: the invoker of dynamic_begin */
/* must test the value against 0. */
#define dynamic_begin(pda, dsize)\
	((pda)->limit =\
		((pda)->base = alloc_dynamic((pda)->size = (dsize), "scanner")) +\
		(dsize),\
	 (pda)->next = (pda)->base)

/* Grow a dynamic object */
private int
dynamic_grow(register dynamic_area *pda)
{	uint size = pda->size;
	uint pos = pda->next - pda->base;
	size = (size >= (uint)(-1) >> 1 ? (uint)(-1) : size << 1);
	pda->base = alloc_grow(pda->base, pda->size, size, "scanner");
	if ( pda->base == 0 ) return 0;
	pda->limit = pda->base + (pda->size = size);
	pda->next = pda->base + pos;
	return 1;
}

/* Get rid of an unwanted dynamic object */
#define dynamic_free(pda)\
  alloc_free((char *)((pda)->base), (pda)->size, "scanner")

/* Initialize the scanner. */
void
scan_init()
{	/* Precompute left and right bracket tokens */
	   {	name_ref("[", 1, &left_bracket, 0);
		r_set_attrs(&left_bracket, a_executable);
		name_ref("]", 1, &right_bracket, 0);
		r_set_attrs(&right_bracket, a_executable);
	   }
	/* Initialize decoder array */
	   {	int i;
		static char hex_chars[] = "0123456789ABCDEFabcdef";
		static char stop_chars[] = "()<>[]{}/%";
		char *p;
		scan_char_decoder[-1] = ctype_eof;
		for ( i = 0; i < 256; i++ )
		  scan_char_decoder[i] = (isspace(i) ? ctype_space : ctype_name);
		for ( i = 0; i < 16+6; i++ )
		  scan_char_decoder[hex_chars[i]] = (i >= 16 ? i - 6 : i);
		for ( p = stop_chars; *p; )
		  scan_char_decoder[*p++] = ctype_other;
		scan_char_decoder[26] = ctype_space; /* ^Z */
	   }
	array_packing = 0;
}

/* Read a token from a stream. */
/* Return 1 for end-of-stream, 0 if a token was read, */
/* or a (negative) error code. */
/* fromString indicates reading from a string vs. a file, */
/* because \ escapes are not recognized in the former case. */
/* (See the footnote on p. 23 of the PostScript manual.) */
int
scan_token(register stream *s, int from_string, ref *pref)
{	ref *myref = pref;
	dynamic_area da;
	int pstack = 0;		/* offset from da.base */
	alloc_end_proc alend = alloc_shrink;
	int retcode = 0;
	register int c;
	int c1;
top:	c = sgetc(s);
#ifdef DEBUG
if ( gs_debug['s'] )
	printf((c >= 32 && c <= 126 ? "`%c'" : "`%03o'"), c);
#endif
	switch ( c )
	   {
	case ' ': case '\t': case '\n': case '\r':
	case 26:			/* ^Z */
		goto top;
	case '[':
		*myref = left_bracket;
		break;
	case ']':
		*myref = right_bracket;
		break;
	case '<':
		retcode = scan_hex_string(s, myref, alend);
		break;
	case '(':
		retcode = scan_string(s, from_string, myref, alend);
		break;
	case '{':
		if ( pstack == 0 )
		   {	myref = (ref *)dynamic_begin(&da, 20 * sizeof(ref));
			if ( myref == 0 ) return e_VMerror;
		   }
		if ( da.limit - (byte *)myref < 2 * sizeof(ref) )
		   {	da.next = (byte *)myref;
			if ( !dynamic_grow(&da) )
			  return e_VMerror;
			myref = (ref *)da.next;
		   }
		myref->size = pstack;
		myref++;
		pstack = (byte *)myref - da.base;
		alend = alloc_shrink_copy;
		goto top;
	case '>':
	case ')':
		retcode = e_syntaxerror;
		break;
	case '}':
		if ( pstack == 0 )
		   {	retcode = e_syntaxerror;
			break;	
		   }
		   {	ref *ref0 = (ref *)(da.base + pstack);
			uint size = myref - ref0;
			ref *aref = (ref *)alloc(size * sizeof(ref), "scanner");
			if ( aref == 0 ) return e_VMerror;
			memcpy(aref, ref0, size * sizeof(ref));
			myref = ref0 - 1;
			pstack = myref->size;
			if ( pstack == 0 )
			   {	myref = pref;
				alloc_free((char *)da.base, da.size, "scanner");
			   }
			if ( array_packing )
				make_tasv(myref, t_packedarray, a_executable + a_read + a_execute, size, refs, aref);
			else
				make_tasv(myref, t_array, a_executable + a_all, size, refs, aref);
		   }
		break;
	case '/':
	   {	int lookup;
		c = sgetc(s);
		if ( c == '/' )
		   {	lookup = 1;
			c = sgetc(s);
		   }
		else
			lookup = 0;
		retcode = scan_name(s, c, myref);
		if ( retcode >= 0 && lookup && r_type(myref) == t_name )	/* might be a number */
		   {	/* Look up the name now. */
			ref *pvalue = dict_search(myref, dsp);
			if ( pvalue == 0 )
				retcode = e_undefined;
			else
				store(myref, *pvalue);
		   }
	   }
		break;
	case '%':
		do { c = sgetc(s); }
		while ( c != '\n' && c != '\r' && c != EOFC );
		if ( c == '\r' && (c1 = sgetc(s)) != '\n' && c1 != EOFC )
			sputback(s);
		if ( c != EOFC ) goto top;
	case EOFC:
		retcode = (pstack != 0 ? e_syntaxerror : 1);
		break;
	/* Add enough cases to force the compiler to generate */
	/* a dispatch rather than a comparison loop. */
	/* What a nuisance! */
	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
	case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm':
	case 'n': case 'o': case 'p': case 'q': case 'r': case 's':
	case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
	default:
		retcode = scan_name(s, c, myref);
		if ( r_type(myref) == t_name )	/* might be a number */
			r_set_attrs(myref, a_executable);
	   }
	/* If we are the top level, return the object, otherwise keep going */
	if ( pstack == 0 || retcode < 0 )
	  return retcode;
	if ( da.limit - (byte *)myref < 2 * sizeof(ref) )
	   {	da.next = (byte *)myref;
		if ( !dynamic_grow(&da) )
		  return e_VMerror;		/* out of room */
		myref = (ref *)da.next;
	   }
	myref++;
	goto top;
}

/* The internal scanning procedures return 0 on success, */
/* or a (negative) error code on failure. */

/* Internal procedure to scan a name. */
private int
scan_name(register stream *s, register int c, ref *pref)
{	dynamic_area da;
	register byte *ptr;
	register char *decoder = scan_char_decoder;
	int try_number;
	int code;
	/* See if this name might be a number */
skip:	switch ( decoder[c] )
	  {
	  case ctype_space:
	    c = sgetc(s);
	    goto skip;
	  case ctype_name:
	    try_number = (c == '+' || c == '-' || c == '.');
	    break;
	  case ctype_other:
	    switch ( c )
	      {
	      case '[':		/* only special as first character */
		*pref = left_bracket;
		r_clear_attrs(pref, a_executable);
		return 0;
	      case ']':		/* ditto */
		*pref = right_bracket;
		r_clear_attrs(pref, a_executable);
		return 0;
	      default:
		return e_syntaxerror;
	      }
	  case ctype_eof:	/* eof following / */
	    return e_syntaxerror;
	  default:
	    try_number = isdigit(c);
	  }
	ptr = dynamic_begin(&da, 40);
	if ( ptr == 0 ) return e_VMerror;
	while ( 1 )
	  {	if ( ptr == da.limit )
		   {	da.next = ptr;
			if ( !dynamic_grow(&da) )
			  return e_VMerror;
			ptr = da.next;
		   }
		*ptr++ = c;
		c = sgetc(s);
		switch ( decoder[c] )
		  {
		  case ctype_other:
			sputback(s);
		  case ctype_space:
			/* Check for \r\n */
			if ( c == '\r' && (c = sgetc(s)) != '\n' && c != EOFC )
				sputback(s);
		  case ctype_eof:
			goto nx;
		  }
	   }
nx:	/* Check for a number */
	if ( try_number )
	   {	stream nst;
		stream *ns = &nst;
		sread_string(ns, da.base, (uint)(ptr - da.base));
		code = scan_number(ns, pref);
		if ( code != e_syntaxerror )
		   {	dynamic_free(&da);
			return code;	/* might be e_limitcheck */
		   }
	   }
	code = name_ref(da.base, (uint)(ptr - da.base), pref, 1);
	dynamic_free(&da);
	return code;
}

/* Procedure to scan a number.  This is also called by cvi and cvr. */
int
scan_number(register stream *s, ref *pref)
{	int sign = 0;
	ulong ival;
	double dval;
	int code;
	register int c;
	switch ( c = sgetc(s) )
	   {
	case '+': sign = 1; c = sgetc(s); break;
	case '-': sign = -1; c = sgetc(s); break;
	   }
	if ( !isdigit(c) )
	   {	if ( c != '.' ) return e_syntaxerror;
		c = sgetc(s);
		if ( !isdigit(c) ) return e_syntaxerror;
		goto ff;
	   }
	sputback(s);
	if ( (code = scan_int(s, 10, &ival, &dval)) != 0 )
	   {	if ( code < 0 ) return code;	/* e_syntaxerror */
		/* Code == 1, i.e., the integer overflowed. */
		switch ( c = sgetc(s) )
		   {
		default: return e_syntaxerror;	/* not terminated properly */
		case '.': c = sgetc(s); goto ff;
		case EOFC:		/* return a float */
			make_real(pref, (float)(sign < 0 ? -dval : dval));
			return 0;
		   }
	   }
	switch ( c = sgetc(s) )
	   {
	default: return e_syntaxerror;	/* not terminated properly */
	case '.': dval = ival; c = sgetc(s); goto ff;
	case '#':
		if ( sign || ival < 2 || ival > 36 ) return e_syntaxerror;
		code = scan_int(s, (int)ival, &ival, NULL);
		if ( code ) return code;
		if ( sgetc(s) != EOFC ) return e_syntaxerror;
	case EOFC: ;
	   }
	/* Return an integer */
	make_int(pref, (sign < 0 ? -ival : ival));
	return 0;
	/* Handle a real.  We just saw the decimal point. */
ff:	   {	int exp10 = 0;
		double epow;
		while ( isdigit(c) )
		   {	dval = dval * 10 + (c - '0');
			c = sgetc(s);
			exp10--;
		   }
		if ( c == 'e' || c == 'E' )
		   {	/* Check for a following exponent. */
			int esign = 0;
			ulong eexp;
			switch ( c = sgetc(s) )
			   {
			case '+': break;
			case '-': esign = 1; break;
			default: sputback(s);
			   }
			code = scan_int(s, 10, &eexp, NULL);
			if ( code < 0 ) return code;
			if ( code > 0 || eexp > 999 )
				return e_limitcheck;	/* semi-arbitrary */
			if ( esign )
				exp10 -= (int)eexp;
			else
				exp10 += (int)eexp;
			c = sgetc(s);
		   }
		if ( c != EOFC ) return e_syntaxerror;
		/* Compute dval * 10^exp10. */
		/* The following doesn't produce very accurate results, */
		/* but it's simple and will do for now. */
		if ( exp10 >= 0 ) epow = 10.0;
		else exp10 = -exp10, epow = 0.1;
		while ( exp10 )
		   {	if ( exp10 & 1 ) dval *= epow;
			exp10 >>= 1;
			epow *= epow;
		   }
		make_real(pref, (float)(sign < 0 ? -dval : dval));
	   }
	return 0;
}
/* Internal subroutine to scan an integer. */
/* Return 0, e_limitcheck, or e_syntaxerror. */
/* (The only syntax error is no digits encountered.) */
/* If pdval == NULL, return e_limitcheck if the integer won't fit; */
/* if pdval != NULL, return 1 and store a double value in *pdval. */
/* Put back the terminating character. */
private int
scan_int(register stream *s, int radix, ulong *pval, double *pdval)
{	ulong ival = 0;
	double dval;
	ulong imax = (ulong)(-1) / radix;
	int irem = (ulong)(-1) % radix;
	register int c;
	while ( 1 )
	   {	c = sgetc(s);
		if ( isdigit(c) ? (c -= '0') >= radix :
		     isalpha(c) ? (c = toupper(c) - ('A' - 10)) >= radix :
		     1
		   )
		   {	if ( c != EOFC ) sputback(s);
			*pval = ival;
			return 0;
		   }
		if ( ival >= imax && (ival > imax || c > irem) )
			break;		/* overflow */
		ival = ival * radix + c;
	   }
	/* Integer overflowed.  Accumulate the result as a double. */
	if ( pdval == NULL ) return e_limitcheck;
	dval = (double)ival * radix + c;
	while ( 1 )
	   {	c = sgetc(s);
		if ( isdigit(c) ? (c -= '0') >= radix :
		     isalpha(c) ? (c = toupper(c) - ('A' - 10)) >= radix :
		     1
		   )
		   {	if ( c != EOFC ) sputback(s);
			*pdval = dval;
			return 1;
		   }
		dval = dval * radix + c;
	   }
}

/* Make a string */
private int
mk_string(ref *pref, dynamic_area *pda, alloc_end_proc alend)
{	uint size = pda->next - pda->base;
	byte *body = (*alend)(pda->base, pda->size, size, "scanner(string)");
	if ( body == 0 ) return e_VMerror;
	make_tasv(pref, t_string, a_all, size, bytes, body);
	return 0;
}

/* Internal procedure to scan a string. */
private int
scan_string(register stream *s, int from_string, ref *pref,
  alloc_end_proc alend)
{	dynamic_area da;
	register int c;
	register byte *ptr = dynamic_begin(&da, 100);
	int plevel = 0;
	if ( ptr == 0 ) return e_VMerror;
top:	while ( 1 )
	   {	c = sgetc(s);
		if ( c == EOFC ) return e_syntaxerror;
		else if ( c == '(' ) plevel++;
		else if ( c == ')' ) { if ( --plevel < 0 ) break; }
		else if ( c == '\\' && !from_string )
		   {	c = sgetc(s);
			switch ( c )
			   {
			case 'n': c = '\n'; break;
			case 'r': c = '\r'; break;
			case 't': c = '\t'; break;
			case 'b': c = '\b'; break;
			case 'f': c = '\f'; break;
			case '\n': goto top;	/* ignore */
			case '0': case '1': case '2': case '3':
			case '4': case '5': case '6': case '7':
			   {	int d = sgetc(s);
				c -= '0';
				if ( d >= '0' && d <= '7' )
				   {	c = (c << 3) + d - '0';
					d = sgetc(s);
					if ( d >= '0' && d <= '7' )
					   {	c = (c << 3) + d - '0';
						break;
					   }
				   }
				if ( d == EOFC ) return e_syntaxerror;
				sputback(s);
			   }
				break;
			default: ;	/* ignore the \ */
			   }
		   }
		if ( ptr == da.limit )
		   {	da.next = ptr;
			if ( !dynamic_grow(&da) )
			  return e_VMerror;
			ptr = da.next;
		   }
		*ptr++ = c;
	   }
	da.next = ptr;
	return mk_string(pref, &da, alend);
}

/* Internal procedure to scan a hex string. */
private int
scan_hex_string(stream *s, ref *pref, alloc_end_proc alend)
{	dynamic_area da;
	int c1, c2, val1, val2;
	byte *ptr = dynamic_begin(&da, 40);
	if ( ptr == 0 ) return e_VMerror;
l1:	do
	   {	c1 = sgetc(s);
		if ( (val1 = scan_char_decoder[c1]) < 0x10 )
		   {	do
			   {	c2 = sgetc(s);
				if ( (val2 = scan_char_decoder[c2]) < 0x10 )
				   {	if ( ptr == da.limit )
					   {	da.next = ptr;
						if ( !dynamic_grow(&da) )
						  return e_VMerror;
						ptr = da.next;
					   }
					*ptr++ = (val1 << 4) + val2;
					goto l1;
				   }
			   }
			while ( val2 == ctype_space );
			if ( c2 != '>' ) return e_syntaxerror;
			if ( ptr == da.limit )
			   {	da.next = ptr;
				if ( !dynamic_grow(&da) )
				  return e_VMerror;
				ptr = da.next;
			   }
			*ptr++ = val1 << 4;	/* no 2nd char */
			goto lx;
		   }
	   }
	while ( val1 == ctype_space );
	if ( c1 != '>' ) return e_syntaxerror;
lx:	da.next = ptr;
	return mk_string(pref, &da, alend);
}