blob: dbb7ecfadf78f7e2c27fd6dfc0031550d9bdd67f [file] [log] [blame]
/* Copyright (C) 1989, 1990 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. */
/* ztype.c */
/* Type, attribute, and conversion operators for GhostScript */
#include "math_.h"
#include "memory_.h"
#include "ghost.h"
#include "errors.h"
#include "oper.h"
#include "dict.h"
#include "name.h"
#include "store.h"
#include "stream.h"
/* Imported values */
extern ref dstack[]; /* for systemdict */
#define systemdict (dstack[0])
/* Forward references */
private int access_check(P3(ref *, int, int));
/* Max and min integer values expressed as reals. */
/* Note that these are biased by 1 to correct for truncation. */
#define lb_real_int (-0x8000L * 1.0 * 0x10000L - 1)
#define ub_real_int (0x8000L * 1.0 * 0x10000L)
/* Get the pointer to the access flags for a ref. */
#define access_ref(opp)\
(r_type(opp) == t_dictionary ? dict_access_ref(opp) : opp)
/* .typenumber */
int
ztypenumber(register ref *op)
{ check_op(1);
make_int(op, r_btype(op));
return 0;
}
/* cvlit */
int
zcvlit(register ref *op)
{ ref *aop;
check_op(1);
aop = access_ref(op);
r_clear_attrs(aop, a_executable);
return 0;
}
/* cvx */
int
zcvx(register ref *op)
{ ref *aop;
check_op(1);
aop = access_ref(op);
r_set_attrs(aop, a_executable);
return 0;
}
/* xcheck */
int
zxcheck(register ref *op)
{ check_op(1);
make_bool(op, (r_attrs(access_ref(op)) & a_executable ? 1 : 0));
return 0;
}
/* executeonly */
int
zexecuteonly(register ref *op)
{ check_op(1);
if ( r_type(op) == t_dictionary ) return e_typecheck;
return access_check(op, a_execute, 1);
}
/* noaccess */
int
znoaccess(register ref *op)
{ return access_check(op, 0, 1);
}
/* readonly */
int
zreadonly(register ref *op)
{ return access_check(op, a_read+a_execute, 1);
}
/* rcheck */
int
zrcheck(register ref *op)
{ int code = access_check(op, a_read, 0);
if ( code >= 0 ) make_bool(op, code);
return code;
}
/* wcheck */
int
zwcheck(register ref *op)
{ int code = access_check(op, a_write, 0);
if ( code >= 0 ) make_bool(op, code);
return code;
}
/* cvi */
int
zcvi(register ref *op)
{ float fval;
switch ( r_type(op) )
{
case t_integer: return 0;
case t_real: fval = op->value.realval; break;
default: return e_typecheck;
case t_string:
{ stream st;
ref nref;
int code;
check_read(*op);
sread_string(&st, op->value.bytes, op->size);
code = scan_number(&st, &nref);
if ( code ) return code; /* error condition */
if ( sgetc(&st) != EOFC ) return e_syntaxerror;
if ( r_type(&nref) == t_integer ) { *op = nref; return 0; }
/* Otherwise, result was a real */
fval = nref.value.realval;
}
}
/* Check if a real will fit into an integer value */
if ( fval <= lb_real_int || fval >= ub_real_int )
return e_rangecheck;
make_int(op, (long)fval); /* truncates towards 0 */
return 0;
}
/* cvn */
int
zcvn(register ref *op)
{ int exec;
int code;
check_read_type(*op, t_string);
exec = r_attrs(op) & a_executable;
code = name_ref(op->value.bytes, op->size, op, 1);
if ( code ) return code;
r_set_attrs(op, exec);
return 0;
}
/* cvr */
int
zcvr(register ref *op)
{ switch ( r_type(op) )
{
case t_integer: make_real(op, op->value.intval);
case t_real: return 0;
default: return e_typecheck;
case t_string:
{ stream st;
ref nref;
int code;
check_read(*op);
sread_string(&st, op->value.bytes, op->size);
code = scan_number(&st, &nref);
if ( code ) return code; /* error condition */
if ( sgetc(&st) != EOFC ) return e_syntaxerror;
if ( r_type(&nref) == t_real ) { *op = nref; return 0; }
/* Otherwise, result was an integer */
make_real(op, nref.value.intval);
return 0;
}
}
}
/* cvrs */
int
zcvrs(register ref *op)
{ int radix;
long ival;
ulong val;
byte digits[31];
byte *endp = &digits[31];
byte *dp = endp;
check_type(op[-1], t_integer);
if ( op[-1].value.intval < 2 || op[-1].value.intval > 36 )
return e_rangecheck;
radix = op[-1].value.intval;
check_write_type(*op, t_string);
switch ( r_type(op - 2) )
{
case t_integer: ival = op[-2].value.intval; break;
case t_real: /****** SHOULD USE cvi HERE ******/
default:
return e_typecheck;
}
val = (ival < 0 ? -ival : ival);
do
{ int dit = val % radix;
*--dp = dit + (dit < 10 ? '0' : ('A' - 10));
val /= radix;
}
while ( val );
if ( ival < 0 ) *--dp = '-';
if ( endp - dp > op->size ) return e_rangecheck;
memcpy(op->value.bytes, dp, (uint)(endp - dp));
op->size = endp - dp;
r_set_attrs(op, a_subrange);
op[-2] = *op;
pop(2);
return 0;
}
/* cvs */
int
zcvs(register ref *op)
{ ref *op1 = op - 1;
char buf[25]; /* big enough for any float */
ref stref;
check_write_type(*op, t_string);
stref.value.bytes = (byte *)buf;
switch ( r_btype(op1) )
{
case t_boolean:
stref.value.bytes =
(byte *)(op1->value.index ? "true" : "false");
break;
case t_integer:
sprintf(buf, "%ld", op1->value.intval);
break;
case t_name:
name_string_ref(op1, &stref); /* name string */
goto nl;
case t_operator:
{ /* Get the name by enumerating systemdict. */
int pos = dict_first(&systemdict);
ref entry[2];
while ( (pos = dict_next(&systemdict, pos, entry)) >= 0 )
{ if ( (long)op1->value.opproc ==
(long)entry[1].value.opproc &&
r_type(&entry[0]) == t_name
)
{ /* Found it. */
name_string_ref(&entry[0], &stref);
goto nl;
}
}
}
/* Can't find it (shouldn't happen...). */
sprintf(buf, "operator %lx", (ulong)op1->value.opproc);
break;
case t_real:
sprintf(buf, "%g", op1->value.realval);
break;
case t_string:
check_read(*op1);
stref = *op1;
goto nl;
default:
check_op(1);
stref.value.bytes = (byte *)"--nostringval--";
}
stref.size = strlen((char *)stref.value.bytes);
nl: if ( stref.size > op->size ) return e_rangecheck;
memcpy(op->value.bytes, stref.value.bytes, stref.size);
op[-1] = *op;
op[-1].size = stref.size;
r_set_attrs(op - 1, a_subrange);
pop(1);
return 0;
}
/* ------ Initialization procedure ------ */
void
ztype_op_init()
{ static op_def my_defs[] = {
{"1cvi", zcvi},
{"1cvlit", zcvlit},
{"1cvn", zcvn},
{"1cvr", zcvr},
{"3cvrs", zcvrs},
{"2cvs", zcvs},
{"1cvx", zcvx},
{"1executeonly", zexecuteonly},
{"1noaccess", znoaccess},
{"1rcheck", zrcheck},
{"1readonly", zreadonly},
{"1.typenumber", ztypenumber},
{"1wcheck", zwcheck},
{"1xcheck", zxcheck},
op_def_end
};
z_op_init(my_defs);
}
/* ------ Internal routines ------ */
/* Test or modify the access of an object. */
/* If modify = 1, restrict to the selected access and return 0; */
/* if modify = 0, return 1 if the object had the access, 0 if not. */
/* Return an error code if the object is not of appropriate type, */
/* or if the object did not have the access already when modify=1. */
private int
access_check(ref *op,
int access, /* mask for attrs */
int modify) /* if true, reduce access */
{ ref *aop = op;
switch ( r_type(op) )
{
default: return e_typecheck;
case t_dictionary:
aop = dict_access_ref(op);
case t_array: case t_file:
case t_packedarray: case t_string: ;
}
if ( modify )
{ if ( ~r_attrs(aop) & access )
return e_invalidaccess;
r_clear_attrs(aop, a_all);
r_set_attrs(aop, access);
return 0;
}
else
{ return (r_attrs(aop) & access) == access;
}
}