386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / iutil.c
CommitLineData
a14dfc57
WJ
1/* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
19
20/* iutil.c */
21/* Utilities for Ghostscript interpreter */
22#include "memory_.h"
23#include "string_.h"
24#include "ghost.h"
25#include "errors.h"
26#include "alloc.h"
27#include "dict.h"
28#include "iutil.h" /* for checking prototypes */
29#include "name.h"
30#include "ostack.h" /* for opdef.h */
31#include "opdef.h" /* for obj_cvs */
32#include "store.h"
33#include "gsmatrix.h"
34#include "gxdevice.h" /* for gx_color_index */
35#include "gzcolor.h"
36
37/* ------ Object utilities ------ */
38
39/* Copy refs from one place to another. */
40void
41refcpy_to_old(register ref *to, register const ref *from, register uint size,
42 const char *cname)
43{ while ( size-- ) ref_assign_old(to, from, cname), to++, from++;
44}
45void
46refcpy_to_new(register ref *to, register const ref *from, register uint size)
47{ while ( size-- ) ref_assign_new(to, from), to++, from++;
48}
49
50/* Fill a new object with nulls. */
51void
52refset_null(register ref *to, register uint size)
53{ while ( size-- ) make_null_new(to), to++;
54}
55
56/* Compare two objects for equality. Return 1 if equal, 0 if not. */
57int
58obj_eq(register const ref *pref1, register const ref *pref2)
59{ ref nref;
60 if ( r_btype(pref1) != r_btype(pref2) )
61 { /* Only a few cases need be considered here: */
62 /* integer/real, name/string, and vice versa. */
63 switch ( r_type(pref1) )
64 {
65 case t_integer:
66 return (r_has_type(pref2, t_real) &&
67 pref2->value.realval == pref1->value.intval);
68 case t_real:
69 return (r_has_type(pref2, t_integer) &&
70 pref2->value.intval == pref1->value.realval);
71 case t_name:
72 if ( !r_has_type(pref2, t_string) ) return 0;
73 name_string_ref(pref1, &nref);
74 pref1 = &nref;
75 break;
76 case t_string:
77 if ( !r_has_type(pref2, t_name) ) return 0;
78 name_string_ref(pref2, &nref);
79 pref2 = &nref;
80 break;
81 default:
82 return 0;
83 }
84 }
85 /* Now do a type-dependent comparison. */
86 /* This would be very simple if we always filled in */
87 /* all 8 bytes of a ref, but we currently don't. */
88 switch ( r_btype(pref1) )
89 {
90 case t_array:
91 return (pref1->value.refs == pref2->value.refs &&
92 r_size(pref1) == r_size(pref2));
93 case t_mixedarray:
94 case t_shortarray:
95 return (pref1->value.packed == pref2->value.packed &&
96 r_size(pref1) == r_size(pref2));
97 case t_boolean:
98 return (pref1->value.index == pref2->value.index);
99 case t_condition:
100 return (pref1->value.pcond == pref2->value.pcond);
101 case t_dictionary:
102 return (pref1->value.pdict == pref2->value.pdict);
103 case t_file:
104 return (pref1->value.pfile == pref2->value.pfile);
105 case t_fontID:
106 return (pref1->value.pfont == pref2->value.pfont);
107 case t_gstate:
108 return (pref1->value.pgstate == pref2->value.pgstate);
109 case t_integer:
110 return (pref1->value.intval == pref2->value.intval);
111 case t_lock:
112 return (pref1->value.plock == pref2->value.plock);
113 case t_mark:
114 case t_null:
115 return 1;
116 case t_name:
117 return (pref1->value.pname == pref2->value.pname);
118 case t_oparray:
119 case t_operator:
120 return (op_index(pref1) == op_index(pref2));
121 case t_real:
122 return (pref1->value.realval == pref2->value.realval);
123 case t_save:
124 return (pref1->value.psave == pref2->value.psave);
125 case t_string:
126 return (!bytes_compare(pref1->value.bytes, r_size(pref1),
127 pref2->value.bytes, r_size(pref2)));
128 case t_color:
129 { struct gs_color_s
130 *pc1 = pref1->value.pcolor,
131 *pc2 = pref2->value.pcolor;
132 return
133 ( pc1->red == pc2->red && pc1->green == pc2->green &&
134 pc1->blue == pc2->blue && pc1->not_black == pc2->not_black
135 );
136 }
137 case t_device:
138 return (pref1->value.pdevice == pref2->value.pdevice);
139 }
140 return 0; /* shouldn't happen! */
141}
142
143/* Create a printable representation of an object, a la cvs. */
144/* Return 0 if OK, <0 if the destination wasn't large enough. */
145int
146obj_cvs(const ref *op, byte *str, uint len, uint *prlen)
147{ char buf[30]; /* big enough for any float */
148 byte *pstr = (byte *)buf;
149 uint plen;
150 ref nref;
151 switch ( r_btype(op) )
152 {
153 case t_boolean:
154 pstr = (byte *)(op->value.index ? "true" : "false");
155 break;
156 case t_integer:
157 sprintf(buf, "%ld", op->value.intval);
158 break;
159 case t_name:
160 name_string_ref(op, &nref); /* name string */
161cvname: pstr = nref.value.bytes;
162 plen = r_size(&nref);
163 goto nl;
164 case t_oparray:
165 name_index_ref(op_array_nx_table[op_index(op) - op_def_count], &nref);
166 name_string_ref(&nref, &nref);
167 goto cvname;
168 case t_operator:
169 { /* Recover the name from the initialization table. */
170 uint index = op_index(op);
171 if ( index != 0 )
172 { pstr = (byte *)(op_def_table[index]->oname + 1);
173 break;
174 }
175 }
176 /* Internal operator, no name. */
177 sprintf(buf, "operator_%lx", (ulong)op->value.opproc);
178 break;
179 case t_real:
180 sprintf(buf, "%g", op->value.realval);
181 break;
182 case t_string:
183 pstr = op->value.bytes;
184 plen = r_size(op);
185 goto nl;
186 default:
187 pstr = (byte *)"--nostringval--";
188 }
189 plen = strlen((char *)pstr);
190nl: if ( plen > len ) return e_rangecheck;
191 memcpy(str, pstr, plen);
192 *prlen = plen;
193 return 0;
194}
195
196/* ------ String utilities ------ */
197
198/* Convert a C string to a Ghostscript string */
199int
200string_to_ref(const char *cstr, ref *pref, const char *cname)
201{ uint size = strlen(cstr);
202 char *str = alloc(size, 1, cname);
203 if ( str == 0 ) return e_VMerror;
204 memcpy(str, cstr, size);
205 make_tasv(pref, t_string, a_all, size, bytes, (byte *)str);
206 return 0;
207}
208
209/* Convert a Ghostscript string to a C string. */
210/* Return 0 iff the buffer can't be allocated. */
211char *
212ref_to_string(const ref *pref, const char *client_name)
213{ uint size = r_size(pref);
214 char *str = alloc(size + 1, 1, client_name);
215 if ( str == 0 ) return 0;
216 memcpy(str, (char *)pref->value.bytes, size);
217 str[size] = 0;
218 return str;
219}
220
221/* ------ Operand utilities ------ */
222
223/* Get N numeric operands from the stack. */
224/* Return a bit-mask indicating which ones are integers, */
225/* or a (negative) error indication. */
226/* The 1-bit in the bit-mask refers to the bottommost stack entry. */
227/* Store float versions of the operands at pval. */
228int
229num_params(const ref *op, int count, float *pval)
230{ int mask = 0;
231 pval += count;
232 while ( --count >= 0 )
233 { mask <<= 1;
234 switch ( r_type(op) )
235 {
236 case t_real:
237 *--pval = op->value.realval;
238 break;
239 case t_integer:
240 *--pval = op->value.intval;
241 mask++;
242 break;
243 default:
244 return e_typecheck;
245 }
246 op--;
247 }
248 return mask;
249}
250
251/* Get a real parameter. */
252/* If an error is returned, the return value is not updated. */
253int
254real_param(const ref *op, float *pparam)
255{ switch ( r_type(op) )
256 {
257 case t_integer: *pparam = op->value.intval; break;
258 case t_real: *pparam = op->value.realval; break;
259 default: return e_typecheck;
260 }
261 return 0;
262}
263
264/* ------ Matrix utilities ------ */
265
266/* Check for a matrix operand with read access. */
267/* Return 0 if OK, error code if not. */
268/* Store an all-float version of the matrix in *pmat. */
269int
270read_matrix(const ref *op, gs_matrix *pmat)
271{ switch ( r_type(op) )
272 {
273 default: return e_typecheck;
274 case t_array: ;
275 }
276 if ( r_size(op) != 6 ) return e_rangecheck;
277 if ( !r_has_attr(op, a_read) ) return e_invalidaccess;
278 *pmat = *(gs_matrix *)op->value.refs;
279 { ref *pel = (ref *)pmat;
280 int i;
281 for ( i = 0; i < 6; i++ )
282 { switch ( r_type(pel) )
283 {
284 default: return e_typecheck;
285 case t_integer:
286 make_real(pel, pel->value.intval);
287 case t_real: ;
288 }
289 pel++;
290 }
291 }
292 return 0;
293}
294
295/* Check for a matrix operand with write access. */
296/* Return 0 if OK, error code if not. */
297/* Initialize the matrix to an identity matrix */
298/* (to set the types and attributes properly.) */
299int
300write_matrix(register ref *op)
301{ ref *aptr;
302 int i;
303 if ( !r_has_type(op, t_array) ) return e_typecheck;
304 if ( !r_has_attr(op, a_write) ) return e_invalidaccess;
305 if ( r_size(op) != 6 ) return e_rangecheck;
306 aptr = op->value.refs;
307 for ( i = 5; i >= 0; i--, aptr++ )
308 { ref_save(aptr, "write_matrix"); /* we're going to overwrite */
309 }
310 gs_make_identity((gs_matrix *)op->value.refs);
311 return 0;
312}