Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: iutil.c,v 1.11 2004/08/19 19:33:09 stefan Exp $ */
18
/* Utilities for Ghostscript interpreter */
19
#include "math_.h"		/* for fabs */
20
#include "memory_.h"
21
#include "string_.h"
22
#include "ghost.h"
23
#include "ierrors.h"
24
#include "gsccode.h"		/* for gxfont.h */
25
#include "gsmatrix.h"
26
#include "gsutil.h"
27
#include "gxfont.h"
28
#include "strimpl.h"
29
#include "sstring.h"
30
#include "idict.h"
31
#include "imemory.h"
32
#include "iname.h"
33
#include "ipacked.h"		/* for array_get */
34
#include "iutil.h"		/* for checking prototypes */
35
#include "ivmspace.h"
36
#include "oper.h"
37
#include "store.h"
38
 
39
/*
40
 * By design choice, none of the procedures in this file take a context
41
 * pointer (i_ctx_p).  Since a number of them require a gs_dual_memory_t
42
 * for store checking or save bookkeeping, we need to #undef idmemory.
43
 */
44
#undef idmemory
45
 
46
/* ------ Object utilities ------ */
47
 
48
/* Define the table of ref type properties. */
49
const byte ref_type_properties[] = {
50
    REF_TYPE_PROPERTIES_DATA
51
};
52
 
53
/* Copy refs from one place to another. */
54
int
55
refcpy_to_old(ref * aref, uint index, const ref * from,
56
	      uint size, gs_dual_memory_t *idmemory, client_name_t cname)
57
{
58
    ref *to = aref->value.refs + index;
59
    int code = refs_check_space(from, size, r_space(aref));
60
 
61
    if (code < 0)
62
	return code;
63
    /* We have to worry about aliasing.... */
64
    if (to <= from || from + size <= to)
65
	while (size--)
66
	    ref_assign_old(aref, to, from, cname), to++, from++;
67
    else
68
	for (from += size, to += size; size--;)
69
	    from--, to--, ref_assign_old(aref, to, from, cname);
70
    return 0;
71
}
72
void
73
refcpy_to_new(ref * to, const ref * from, uint size,
74
	      gs_dual_memory_t *idmemory)
75
{
76
    while (size--)
77
	ref_assign_new(to, from), to++, from++;
78
}
79
 
80
/* Fill a new object with nulls. */
81
void
82
refset_null_new(ref * to, uint size, uint new_mask)
83
{
84
    for (; size--; ++to)
85
	make_ta(to, t_null, new_mask);
86
}
87
 
88
/* Compare two objects for equality. */
89
bool
90
obj_eq(const gs_memory_t *mem, const ref * pref1, const ref * pref2)
91
{
92
    ref nref;
93
 
94
    if (r_type(pref1) != r_type(pref2)) {
95
	/*
96
	 * Only a few cases need be considered here:
97
	 * integer/real (and vice versa), name/string (and vice versa),
98
	 * arrays, and extended operators.
99
	 */
100
	switch (r_type(pref1)) {
101
	    case t_integer:
102
		return (r_has_type(pref2, t_real) &&
103
			pref2->value.realval == pref1->value.intval);
104
	    case t_real:
105
		return (r_has_type(pref2, t_integer) &&
106
			pref2->value.intval == pref1->value.realval);
107
	    case t_name:
108
		if (!r_has_type(pref2, t_string))
109
		    return false;
110
		name_string_ref(mem, pref1, &nref);
111
		pref1 = &nref;
112
		break;
113
	    case t_string:
114
		if (!r_has_type(pref2, t_name))
115
		    return false;
116
		name_string_ref(mem, pref2, &nref);
117
		pref2 = &nref;
118
		break;
119
 
120
		/* differing array types can match if length is 0 */
121
	    case t_array:
122
	    case t_mixedarray:
123
	    case t_shortarray:
124
		return r_is_array(pref2) &&
125
		       r_size(pref1) == 0 && r_size(pref2) == 0;
126
	    default:
127
		if (r_btype(pref1) != r_btype(pref2))
128
		    return false;
129
	}
130
    }
131
    /*
132
     * Now do a type-dependent comparison.  This would be very simple if we
133
     * always filled in all the bytes of a ref, but we currently don't.
134
     */
135
    switch (r_btype(pref1)) {
136
	case t_array:
137
	    return ((pref1->value.refs == pref2->value.refs ||
138
	             r_size(pref1) == 0) &&
139
		    r_size(pref1) == r_size(pref2));
140
	case t_mixedarray:
141
	case t_shortarray:
142
	    return ((pref1->value.packed == pref2->value.packed ||
143
	             r_size(pref1) == 0) &&
144
		    r_size(pref1) == r_size(pref2));
145
	case t_boolean:
146
	    return (pref1->value.boolval == pref2->value.boolval);
147
	case t_dictionary:
148
	    return (pref1->value.pdict == pref2->value.pdict);
149
	case t_file:
150
	    return (pref1->value.pfile == pref2->value.pfile &&
151
		    r_size(pref1) == r_size(pref2));
152
	case t_integer:
153
	    return (pref1->value.intval == pref2->value.intval);
154
	case t_mark:
155
	case t_null:
156
	    return true;
157
	case t_name:
158
	    return (pref1->value.pname == pref2->value.pname);
159
	case t_oparray:
160
	case t_operator:
161
	    return (op_index(pref1) == op_index(pref2));
162
	case t_real:
163
	    return (pref1->value.realval == pref2->value.realval);
164
	case t_save:
165
	    return (pref2->value.saveid == pref1->value.saveid);
166
	case t_string:
167
	    return (!bytes_compare(pref1->value.bytes, r_size(pref1),
168
				   pref2->value.bytes, r_size(pref2)));
169
	case t_device:
170
	    return (pref1->value.pdevice == pref2->value.pdevice);
171
	case t_struct:
172
	case t_astruct:
173
	    return (pref1->value.pstruct == pref2->value.pstruct);
174
	case t_fontID:
175
	    {	/*
176
		 * In the Adobe implementations, different scalings of a
177
		 * font have "equal" FIDs, so we do the same.
178
		 */
179
		const gs_font *pfont1 = r_ptr(pref1, gs_font);
180
		const gs_font *pfont2 = r_ptr(pref2, gs_font);
181
 
182
		while (pfont1->base != pfont1)
183
		    pfont1 = pfont1->base;
184
		while (pfont2->base != pfont2)
185
		    pfont2 = pfont2->base;
186
		return (pfont1 == pfont2);
187
	    }
188
    }
189
    return false;		/* shouldn't happen! */
190
}
191
 
192
/* Compare two objects for identity. */
193
bool
194
obj_ident_eq(const gs_memory_t *mem, const ref * pref1, const ref * pref2)
195
{
196
    if (r_type(pref1) != r_type(pref2))
197
	return false;
198
    if (r_has_type(pref1, t_string))
199
	return (pref1->value.bytes == pref2->value.bytes &&
200
		r_size(pref1) == r_size(pref2));
201
    return obj_eq(mem, pref1, pref2);
202
}
203
 
204
/*
205
 * Set *pchars and *plen to point to the data of a name or string, and
206
 * return 0.  If the object isn't a name or string, return e_typecheck.
207
 * If the object is a string without read access, return e_invalidaccess.
208
 */
209
int
210
obj_string_data(const gs_memory_t *mem, const ref *op, const byte **pchars, uint *plen)
211
{
212
    switch (r_type(op)) {
213
    case t_name: {
214
	ref nref;
215
 
216
	name_string_ref(mem, op, &nref);
217
	*pchars = nref.value.bytes;
218
	*plen = r_size(&nref);
219
	return 0;
220
    }
221
    case t_string:
222
	check_read(*op);
223
	*pchars = op->value.bytes;
224
	*plen = r_size(op);
225
	return 0;
226
    default:
227
	return_error(e_typecheck);
228
    }
229
}
230
 
231
/*
232
 * Create a printable representation of an object, a la cvs and =
233
 * (full_print = 0), == (full_print = 1), or === (full_print = 2).  Return 0
234
 * if OK, 1 if the destination wasn't large enough, e_invalidaccess if the
235
 * object's contents weren't readable.  If the return value is 0 or 1,
236
 * *prlen contains the amount of data returned.  start_pos is the starting
237
 * output position -- the first start_pos bytes of output are discarded.
238
 *
239
 * The mem argument is only used for getting the type of structures,
240
 * not for allocating; if it is NULL and full_print != 0, structures will
241
 * print as --(struct)--.
242
 *
243
 * This rather complex API is needed so that a client can call obj_cvp
244
 * repeatedly to print on a stream, which may require suspending at any
245
 * point to handle stream callouts.
246
 */
247
private void ensure_dot(char *);
248
int
249
obj_cvp(const ref * op, byte * str, uint len, uint * prlen,
250
	int full_print, uint start_pos, const gs_memory_t *mem)
251
{
252
    char buf[50];  /* big enough for any float, double, or struct name */
253
    const byte *data = (const byte *)buf;
254
    uint size;
255
    int code;
256
    ref nref;
257
 
258
    if (full_print) {
259
	static const char * const type_strings[] = { REF_TYPE_PRINT_STRINGS };
260
 
261
	switch (r_btype(op)) {
262
	case t_boolean:
263
	case t_integer:
264
	    break;
265
	case t_real: {
266
	    /*
267
	     * To get fully accurate output results for IEEE
268
	     * single-precision floats (24 bits of mantissa), the ANSI %g
269
	     * default of 6 digits is not enough; 9 are needed.
270
	     * Unfortunately, using %.9g for floats (as opposed to doubles)
271
	     * produces unfortunate artifacts such as 0.01 5 mul printing as
272
	     * 0.049999997.  Therefore, we print using %g, and if the result
273
	     * isn't accurate enough, print again using %.9g.
274
	     * Unfortunately, a few PostScript programs 'know' that the
275
	     * printed representation of floats fits into 6 digits (e.g.,
276
	     * with cvs).  We resolve this by letting cvs, cvrs, and = do
277
	     * what the Adobe interpreters appear to do (use %g), and only
278
	     * produce accurate output for ==, for which there is no
279
	     * analogue of cvs.  What a hack!
280
	     */
281
	    float value = op->value.realval;
282
	    float scanned;
283
 
284
	    sprintf(buf, "%g", value);
285
	    sscanf(buf, "%f", &scanned);
286
	    if (scanned != value)
287
		sprintf(buf, "%.9g", value);
288
	    ensure_dot(buf);
289
	    goto rs;
290
	}
291
	case t_operator:
292
	case t_oparray:  
293
	    code = obj_cvp(op, (byte *)buf + 2, sizeof(buf) - 4, &size, 0, 0, mem);
294
	    if (code < 0) 
295
		return code;
296
	    buf[0] = buf[1] = buf[size + 2] = buf[size + 3] = '-';
297
	    size += 4;
298
	    goto nl;
299
	case t_name:	 
300
	    if (r_has_attr(op, a_executable)) {
301
		code = obj_string_data(mem, op, &data, &size);
302
		if (code < 0)
303
		    return code;
304
		goto nl;
305
	    }
306
	    if (start_pos > 0)
307
		return obj_cvp(op, str, len, prlen, 0, start_pos - 1, mem);
308
	    if (len < 1)
309
		return_error(e_rangecheck);
310
	    code = obj_cvp(op, str + 1, len - 1, prlen, 0, 0, mem);
311
	    if (code < 0)
312
		return code;
313
	    str[0] = '/';
314
	    ++*prlen;
315
	    return code;
316
	case t_null:
317
	    data = (const byte *)"null";
318
	    goto rs;
319
	case t_string:  
320
	    if (!r_has_attr(op, a_read))
321
		goto other;
322
	    size = r_size(op);
323
	    {
324
		bool truncate = (full_print == 1 && size > CVP_MAX_STRING);
325
		stream_cursor_read r;
326
		stream_cursor_write w;
327
		uint skip;
328
		byte *wstr;
329
		uint len1;
330
		int status = 1;
331
 
332
		if (start_pos == 0) {
333
		    if (len < 1)
334
			return_error(e_rangecheck);
335
		    str[0] = '(';
336
		    skip = 0;
337
		    wstr = str + 1;
338
		} else {
339
		    skip = start_pos - 1;
340
		    wstr = str;
341
		}
342
		len1 = len + (str - wstr);
343
		r.ptr = op->value.const_bytes - 1;
344
		r.limit = r.ptr + (truncate ? CVP_MAX_STRING : size);
345
		while (skip && status == 1) {
346
		    uint written;
347
 
348
		    w.ptr = (byte *)buf - 1;
349
		    w.limit = w.ptr + min(skip + len1, sizeof(buf));
350
		    status = s_PSSE_template.process(NULL, &r, &w, false);
351
		    written = w.ptr - ((byte *)buf - 1);
352
		    if (written > skip) {
353
			written -= skip;
354
			memcpy(wstr, buf + skip, written);
355
			wstr += written;
356
			skip = 0;
357
			break;
358
		    }
359
		    skip -= written;
360
		}
361
		/*
362
		 * We can reach here with status == 0 (and skip != 0) if
363
		 * start_pos lies within the trailing ")" or  "...)".
364
		 */
365
		if (status == 0) {
366
#ifdef DEBUG
367
		    if (skip > (truncate ? 4 : 1)) {
368
			return_error(e_Fatal);
369
		    }
370
#endif
371
		}
372
		w.ptr = wstr - 1;
373
		w.limit = str - 1 + len;
374
		if (status == 1)
375
		    status = s_PSSE_template.process(NULL, &r, &w, false);
376
		*prlen = w.ptr - (str - 1);
377
		if (status != 0)
378
		    return 1;
379
		if (truncate) {
380
		    if (len - *prlen < 4 - skip)
381
			return 1;
382
		    memcpy(w.ptr + 1, "...)" + skip, 4 - skip);
383
		    *prlen += 4 - skip;
384
		} else {
385
		    if (len - *prlen < 1 - skip)
386
			return 1;
387
		    memcpy(w.ptr + 1, ")" + skip, 1 - skip);
388
		    *prlen += 1 - skip;
389
		}
390
	    }
391
	    return 0;
392
	case t_astruct:
393
	case t_struct:    
394
	    if (r_is_foreign(op)) {
395
		/* gs_object_type may not work. */
396
		data = (const byte *)"-foreign-struct-";
397
		goto rs;
398
	    }
399
	    if (!mem) {
400
		data = (const byte *)"-(struct)-";
401
		goto rs;
402
	    }
403
	    data = (const byte *)
404
		gs_struct_type_name_string(
405
		     gs_object_type((gs_memory_t *)mem,
406
				    (const obj_header_t *)op->value.pstruct));
407
	    size = strlen((const char *)data);
408
	    if (size > 4 && !memcmp(data + size - 4, "type", 4))
409
		size -= 4;
410
	    if (size > sizeof(buf) - 2)
411
		return_error(e_rangecheck);
412
	    buf[0] = '-';
413
	    memcpy(buf + 1, data, size);
414
	    buf[size + 1] = '-';
415
	    size += 2;
416
	    data = (const byte *)buf;
417
	    goto nl;
418
	default:
419
other:
420
	    {
421
		int rtype = r_btype(op);
422
 
423
		if (rtype > countof(type_strings))
424
		    return_error(e_rangecheck);
425
		data = (const byte *)type_strings[rtype];
426
		if (data == 0)
427
		    return_error(e_rangecheck);
428
	    }
429
	    goto rs;
430
	}
431
    }	
432
    /* full_print = 0 */
433
    switch (r_btype(op)) {
434
    case t_boolean:
435
	data = (const byte *)(op->value.boolval ? "true" : "false");
436
	break;
437
    case t_integer:
438
	sprintf(buf, "%ld", op->value.intval);
439
	break;
440
    case t_string:
441
	check_read(*op);
442
	/* falls through */
443
    case t_name:
444
	code = obj_string_data(mem, op, &data, &size);
445
	if (code < 0)
446
	    return code;
447
	goto nl;
448
    case t_oparray: {
449
	uint index = op_index(op);
450
	const op_array_table *opt = op_index_op_array_table(index);
451
 
452
	name_index_ref(mem, opt->nx_table[index - opt->base_index], &nref);
453
	name_string_ref(mem, &nref, &nref);
454
	code = obj_string_data(mem, &nref, &data, &size);
455
	if (code < 0)
456
	    return code;
457
	goto nl;
458
    }
459
    case t_operator: {
460
	/* Recover the name from the initialization table. */
461
	uint index = op_index(op);
462
 
463
	/*
464
	 * Check the validity of the index.  (An out-of-bounds index
465
	 * is only possible when examining an invalid object using
466
	 * the debugger.)
467
	 */
468
	if (index > 0 && index < op_def_count) {
469
	    data = (const byte *)(op_index_def(index)->oname + 1);
470
	    break;
471
	}
472
	/* Internal operator, no name. */
473
	sprintf(buf, "@0x%lx", (ulong) op->value.opproc);
474
	break;
475
    }
476
    case t_real:
477
	sprintf(buf, "%g", op->value.realval);
478
	ensure_dot(buf);
479
	break;
480
    default:
481
	data = (const byte *)"--nostringval--";
482
    }
483
rs: size = strlen((const char *)data);
484
nl: if (size < start_pos)
485
	return_error(e_rangecheck);
486
    size -= start_pos;
487
    *prlen = min(size, len);
488
    memmove(str, data + start_pos, *prlen);
489
    return (size > len);
490
}
491
/*
492
 * Make sure the converted form of a real number has a decimal point.  This
493
 * is needed for compatibility with Adobe (and other) interpreters.
494
 */
495
private void
496
ensure_dot(char *buf)
497
{
498
    if (strchr(buf, '.') == NULL) {
499
	char *ept = strchr(buf, 'e');
500
 
501
	if (ept == NULL)
502
	    strcat(buf, ".0");
503
	else {
504
	    /* Insert the .0 before the exponent.  What a nuisance! */
505
	    char buf1[30];
506
 
507
	    strcpy(buf1, ept);
508
	    strcpy(ept, ".0");
509
	    strcat(ept, buf1);
510
	}
511
    }
512
}
513
 
514
/*
515
 * Create a printable representation of an object, a la cvs and =.  Return 0
516
 * if OK, e_rangecheck if the destination wasn't large enough,
517
 * e_invalidaccess if the object's contents weren't readable.  If pchars !=
518
 * NULL, then if the object was a string or name, store a pointer to its
519
 * characters in *pchars even if it was too large; otherwise, set *pchars =
520
 * str.  In any case, store the length in *prlen.
521
 */
522
int
523
obj_cvs(const gs_memory_t *mem, const ref * op, byte * str, uint len, uint * prlen,
524
	const byte ** pchars)
525
{
526
    int code = obj_cvp(op, str, len, prlen, 0, 0, mem);  /* NB: NULL memptr */
527
 
528
    if (code != 1 && pchars) {
529
	*pchars = str;
530
	return code;
531
    }
532
    obj_string_data(mem, op, pchars, prlen);
533
    return gs_note_error(e_rangecheck);
534
}
535
 
536
/* Find the index of an operator that doesn't have one stored in it. */
537
ushort
538
op_find_index(const ref * pref /* t_operator */ )
539
{
540
    op_proc_t proc = real_opproc(pref);
541
    const op_def *const *opp = op_defs_all;
542
    const op_def *const *opend = opp + (op_def_count / OP_DEFS_MAX_SIZE);
543
 
544
    for (; opp < opend; ++opp) {
545
	const op_def *def = *opp;
546
 
547
	for (; def->oname != 0; ++def)
548
	    if (def->proc == proc)
549
		return (opp - op_defs_all) * OP_DEFS_MAX_SIZE + (def - *opp);
550
    }
551
    /* Lookup failed!  This isn't possible.... */
552
    return 0;
553
}
554
 
555
/*
556
 * Convert an operator index to an operator or oparray ref.
557
 * This is only used for debugging and for 'get' from packed arrays,
558
 * so it doesn't have to be very fast.
559
 */
560
void
561
op_index_ref(uint index, ref * pref)
562
{
563
    const op_array_table *opt;
564
 
565
    if (op_index_is_operator(index)) {
566
	make_oper(pref, index, op_index_proc(index));
567
	return;
568
    }
569
    opt = op_index_op_array_table(index);
570
    make_tasv(pref, t_oparray, opt->attrs, index,
571
	      const_refs, (opt->table.value.const_refs
572
			   + index - opt->base_index));
573
}
574
 
575
/* Get an element from an array of some kind. */
576
/* This is also used to index into Encoding vectors, */
577
/* the error name vector, etc. */
578
int
579
array_get(const gs_memory_t *mem, const ref * aref, long index_long, ref * pref)
580
{
581
    if ((ulong)index_long >= r_size(aref))
582
	return_error(e_rangecheck);
583
    switch (r_type(aref)) {
584
	case t_array:
585
	    {
586
		const ref *pvalue = aref->value.refs + index_long;
587
 
588
		ref_assign(pref, pvalue);
589
	    }
590
	    break;
591
	case t_mixedarray:
592
	    {
593
		const ref_packed *packed = aref->value.packed;
594
		uint index = (uint)index_long;
595
 
596
		for (; index--;)
597
		    packed = packed_next(packed);
598
		packed_get(mem, packed, pref);
599
	    }
600
	    break;
601
	case t_shortarray:
602
	    {
603
		const ref_packed *packed = aref->value.packed + index_long;
604
 
605
		packed_get(mem, packed, pref);
606
	    }
607
	    break;
608
	default:
609
	    return_error(e_typecheck);
610
    }
611
    return 0;
612
}
613
 
614
/* Get an element from a packed array. */
615
/* (This works for ordinary arrays too.) */
616
/* Source and destination are allowed to overlap if the source is packed, */
617
/* or if they are identical. */
618
void
619
packed_get(const gs_memory_t *mem, const ref_packed * packed, ref * pref)
620
{
621
    const ref_packed elt = *packed;
622
    uint value = elt & packed_value_mask;
623
 
624
    switch (elt >> r_packed_type_shift) {
625
	default:		/* (shouldn't happen) */
626
	    make_null(pref);
627
	    break;
628
	case pt_executable_operator:
629
	    op_index_ref(value, pref);
630
	    break;
631
	case pt_integer:
632
	    make_int(pref, (int)value + packed_min_intval);
633
	    break;
634
	case pt_literal_name:
635
	    name_index_ref(mem, value, pref);
636
	    break;
637
	case pt_executable_name:
638
	    name_index_ref(mem, value, pref);
639
	    r_set_attrs(pref, a_executable);
640
	    break;
641
	case pt_full_ref:
642
	case pt_full_ref + 1:
643
	    ref_assign(pref, (const ref *)packed);
644
    }
645
}
646
 
647
/* Check to make sure an interval contains no object references */
648
/* to a space younger than a given one. */
649
/* Return 0 or e_invalidaccess. */
650
int
651
refs_check_space(const ref * bot, uint size, uint space)
652
{
653
    for (; size--; bot++)
654
	store_check_space(space, bot);
655
    return 0;
656
}
657
 
658
/* ------ String utilities ------ */
659
 
660
/* Convert a C string to a Ghostscript string */
661
int
662
string_to_ref(const char *cstr, ref * pref, gs_ref_memory_t * mem,
663
	      client_name_t cname)
664
{
665
    uint size = strlen(cstr);
666
    int code = gs_alloc_string_ref(mem, pref, a_all, size, cname);
667
 
668
    if (code < 0)
669
	return code;
670
    memcpy(pref->value.bytes, cstr, size);
671
    return 0;
672
}
673
 
674
/* Convert a Ghostscript string to a C string. */
675
/* Return 0 iff the buffer can't be allocated. */
676
char *
677
ref_to_string(const ref * pref, gs_memory_t * mem, client_name_t cname)
678
{
679
    uint size = r_size(pref);
680
    char *str = (char *)gs_alloc_string(mem, size + 1, cname);
681
 
682
    if (str == 0)
683
	return 0;
684
    memcpy(str, (const char *)pref->value.bytes, size);
685
    str[size] = 0;
686
    return str;
687
}
688
 
689
/* ------ Operand utilities ------ */
690
 
691
/* Get N numeric operands from the stack or an array. */
692
/* Return a bit-mask indicating which ones are integers, */
693
/* or a (negative) error indication. */
694
/* The 1-bit in the bit-mask refers to the first operand. */
695
/* Store float versions of the operands at pval. */
696
/* The stack underflow check (check for t__invalid) is harmless */
697
/* if the operands come from somewhere other than the stack. */
698
int
699
num_params(const ref * op, int count, double *pval)
700
{
701
    int mask = 0;
702
 
703
    pval += count;
704
    while (--count >= 0) {
705
	mask <<= 1;
706
	switch (r_type(op)) {
707
	    case t_real:
708
		*--pval = op->value.realval;
709
		break;
710
	    case t_integer:
711
		*--pval = op->value.intval;
712
		mask++;
713
		break;
714
	    case t__invalid:
715
		return_error(e_stackunderflow);
716
	    default:
717
		return_error(e_typecheck);
718
	}
719
	op--;
720
    }
721
    /* If count is very large, mask might overflow. */
722
    /* In this case we clearly don't care about the value of mask. */
723
    return (mask < 0 ? 0 : mask);
724
}
725
/* float_params doesn't bother to keep track of the mask. */
726
int
727
float_params(const ref * op, int count, float *pval)
728
{
729
    for (pval += count; --count >= 0; --op)
730
	switch (r_type(op)) {
731
	    case t_real:
732
		*--pval = op->value.realval;
733
		break;
734
	    case t_integer:
735
		*--pval = (float)op->value.intval;
736
		break;
737
	    case t__invalid:
738
		return_error(e_stackunderflow);
739
	    default:
740
		return_error(e_typecheck);
741
	}
742
    return 0;
743
}
744
 
745
/* Get N numeric parameters (as floating point numbers) from an array */
746
int
747
process_float_array(const gs_memory_t *mem, const ref * parray, int count, float * pval)
748
{
749
    int         code = 0, indx0 = 0;
750
 
751
    /* we assume parray is an array of some type, of adequate length */
752
    if (r_has_type(parray, t_array))
753
        return float_params(parray->value.refs + count - 1, count, pval);
754
 
755
    /* short/mixed array; convert the entries to refs */
756
    while (count > 0 && code >= 0) {
757
        int     i, subcount;
758
        ref     ref_buff[20];   /* 20 is arbitrary */
759
 
760
        subcount = (count > countof(ref_buff) ? countof(ref_buff) : count);
761
        for (i = 0; i < subcount && code >= 0; i++)
762
            code = array_get(mem, parray, (long)(i + indx0), &ref_buff[i]);
763
        if (code >= 0)
764
            code = float_params(ref_buff + subcount - 1, subcount, pval);
765
        count -= subcount;
766
        pval += subcount;
767
        indx0 += subcount;
768
    }
769
 
770
    return code;
771
}
772
 
773
/* Get a single real parameter. */
774
/* The only possible error is e_typecheck. */
775
/* If an error is returned, the return value is not updated. */
776
int
777
real_param(const ref * op, double *pparam)
778
{
779
    switch (r_type(op)) {
780
	case t_integer:
781
	    *pparam = op->value.intval;
782
	    break;
783
	case t_real:
784
	    *pparam = op->value.realval;
785
	    break;
786
	default:
787
	    return_error(e_typecheck);
788
    }
789
    return 0;
790
}
791
int
792
float_param(const ref * op, float *pparam)
793
{
794
    double dval;
795
    int code = real_param(op, &dval);
796
 
797
    if (code >= 0)
798
	*pparam = (float)dval;	/* can't overflow */
799
    return code;
800
}
801
 
802
/* Get an integer parameter in a given range. */
803
int
804
int_param(const ref * op, int max_value, int *pparam)
805
{
806
    check_int_leu(*op, max_value);
807
    *pparam = (int)op->value.intval;
808
    return 0;
809
}
810
 
811
/* Make real values on the operand stack. */
812
int
813
make_reals(ref * op, const double *pval, int count)
814
{
815
    /* This should return e_limitcheck if any real is too large */
816
    /* to fit into a float on the stack. */
817
    for (; count--; op++, pval++)
818
	make_real(op, *pval);
819
    return 0;
820
}
821
int
822
make_floats(ref * op, const float *pval, int count)
823
{
824
    /* This should return e_undefinedresult for infinities. */
825
    for (; count--; op++, pval++)
826
	make_real(op, *pval);
827
    return 0;
828
}
829
 
830
/* Compute the error code when check_proc fails. */
831
/* Note that the client, not this procedure, uses return_error. */
832
/* The stack underflow check is harmless in the off-stack case. */
833
int
834
check_proc_failed(const ref * pref)
835
{
836
    return (r_is_array(pref) ? e_invalidaccess :
837
	    r_has_type(pref, t__invalid) ? e_stackunderflow :
838
	    e_typecheck);
839
}
840
 
841
/* Compute the error code when a type check on the stack fails. */
842
/* Note that the client, not this procedure, uses return_error. */
843
int
844
check_type_failed(const ref * op)
845
{
846
    return (r_has_type(op, t__invalid) ? e_stackunderflow : e_typecheck);
847
}
848
 
849
/* ------ Matrix utilities ------ */
850
 
851
/* Read a matrix operand. */
852
/* Return 0 if OK, error code if not. */
853
int
854
read_matrix(const gs_memory_t *mem, const ref * op, gs_matrix * pmat)
855
{
856
    int code;
857
    ref values[6];
858
    const ref *pvalues;
859
 
860
    if (r_has_type(op, t_array))
861
	pvalues = op->value.refs;
862
    else {
863
	int i;
864
 
865
	for (i = 0; i < 6; ++i) {
866
	    code = array_get(mem, op, (long)i, &values[i]);
867
	    if (code < 0)
868
		return code;
869
	}
870
	pvalues = values;
871
    }
872
    check_read(*op);
873
    if (r_size(op) != 6)
874
	return_error(e_rangecheck);
875
    code = float_params(pvalues + 5, 6, (float *)pmat);
876
    return (code < 0 ? code : 0);
877
}
878
 
879
/* Write a matrix operand. */
880
/* Return 0 if OK, error code if not. */
881
int
882
write_matrix_in(ref * op, const gs_matrix * pmat, gs_dual_memory_t *idmemory,
883
		gs_ref_memory_t *imem)
884
{
885
    ref *aptr;
886
    const float *pel;
887
    int i;
888
 
889
    check_write_type(*op, t_array);
890
    if (r_size(op) != 6)
891
	return_error(e_rangecheck);
892
    aptr = op->value.refs;
893
    pel = (const float *)pmat;
894
    for (i = 5; i >= 0; i--, aptr++, pel++) {
895
	if (idmemory) {
896
	    ref_save(op, aptr, "write_matrix");
897
	    make_real_new(aptr, *pel);
898
	} else {
899
	    make_tav(aptr, t_real, imemory_new_mask(imem), realval, *pel);
900
	}
901
    }
902
    return 0;
903
}