xref: /plan9-contrib/sys/src/cmd/gs/src/zfunc.c (revision d46c239f8612929b7dbade67d0d071633df3a15d)
1 /* Copyright (C) 1997, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This file is part of AFPL Ghostscript.
4 
5   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
6   distributor accepts any responsibility for the consequences of using it, or
7   for whether it serves any particular purpose or works at all, unless he or
8   she says so in writing.  Refer to the Aladdin Free Public License (the
9   "License") for full details.
10 
11   Every copy of AFPL Ghostscript must include a copy of the License, normally
12   in a plain ASCII text file named PUBLIC.  The License grants you the right
13   to copy, modify and redistribute AFPL Ghostscript, but only under certain
14   conditions described in the License.  Among other things, the License
15   requires that the copyright notice and this notice be preserved on all
16   copies.
17 */
18 
19 /*$Id: zfunc.c,v 1.6.6.2 2002/01/17 06:57:55 dancoby Exp $ */
20 /* Generic PostScript language interface to Functions */
21 #include "memory_.h"
22 #include "ghost.h"
23 #include "oper.h"
24 #include "gscdefs.h"
25 #include "gsfunc.h"
26 #include "gsstruct.h"
27 #include "ialloc.h"
28 #include "idict.h"
29 #include "idparam.h"
30 #include "ifunc.h"
31 #include "store.h"
32 
33 /* Define the maximum depth of nesting of subsidiary functions. */
34 #define MAX_SUB_FUNCTION_DEPTH 3
35 
36 /* GC descriptors */
37 gs_private_st_ptr(st_function_ptr, gs_function_t *, "gs_function_t *",
38 		  function_ptr_enum_ptrs, function_ptr_reloc_ptrs);
39 gs_private_st_element(st_function_ptr_element, gs_function_t *,
40 		      "gs_function_t *[]", function_ptr_element_enum_ptrs,
41 		      function_ptr_element_reloc_ptrs, st_function_ptr);
42 
43 /* ------ Operators ------ */
44 
45 /* <dict> .buildfunction <function_struct> */
46 private int
47 zbuildfunction(i_ctx_t *i_ctx_p)
48 {
49     os_ptr op = osp;
50     gs_function_t *pfn;
51     ref cref;			/* closure */
52     int code;
53 
54     code = ialloc_ref_array(&cref, a_executable | a_execute, 2,
55 			    ".buildfunction");
56     if (code < 0)
57 	return code;
58     code = fn_build_function(i_ctx_p, op, &pfn, imemory);
59     if (code < 0) {
60 	ifree_ref_array(&cref, ".buildfunction");
61 	return code;
62     }
63     make_istruct_new(cref.value.refs, a_executable | a_execute, pfn);
64     make_oper_new(cref.value.refs + 1, 0, zexecfunction);
65     ref_assign(op, &cref);
66     return 0;
67 }
68 
69 /* <in1> ... <function_struct> %execfunction <out1> ... */
70 int
71 zexecfunction(i_ctx_t *i_ctx_p)
72 {
73     os_ptr op = osp;
74 
75 	/*
76 	 * Since this operator's name begins with %, the name is not defined
77 	 * in systemdict.  The only place this operator can ever appear is
78 	 * in the execute-only closure created by .buildfunction.
79 	 * Therefore, in principle it is unnecessary to check the argument.
80 	 * However, we do a little checking anyway just on general
81 	 * principles.  Note that since the argument may be an instance of
82 	 * any subclass of gs_function_t, we currently have no way to check
83 	 * its type.
84 	 */
85     if (!r_is_struct(op) ||
86 	!r_has_masked_attrs(op, a_executable | a_execute, a_executable | a_all)
87 	)
88 	return_error(e_typecheck);
89     {
90 	gs_function_t *pfn = (gs_function_t *) op->value.pstruct;
91 	int m = pfn->params.m, n = pfn->params.n;
92 	int diff = n - (m + 1);
93 
94 	if (diff > 0)
95 	    check_ostack(diff);
96 	{
97 	    float params[20];	/* arbitrary size, just to avoid allocs */
98 	    float *in;
99 	    float *out;
100 	    int code = 0;
101 
102 	    if (m + n <= countof(params)) {
103 		in = params;
104 	    } else {
105 		in = (float *)ialloc_byte_array(m + n, sizeof(float),
106 						"%execfunction(in/out)");
107 		if (in == 0)
108 		    code = gs_note_error(e_VMerror);
109 	    }
110 	    out = in + m;
111 	    if (code < 0 ||
112 		(code = float_params(op - 1, m, in)) < 0 ||
113 		(code = gs_function_evaluate(pfn, in, out)) < 0
114 		)
115 		DO_NOTHING;
116 	    else {
117 		if (diff > 0)
118 		    push(diff);	/* can't fail */
119 		else if (diff < 0) {
120 		    pop(-diff);
121 		    op = osp;
122 		}
123 		code = make_floats(op + 1 - n, out, n);
124 	    }
125 	    if (in != params)
126 		ifree_object(in, "%execfunction(in)");
127 	    return code;
128 	}
129     }
130 }
131 
132 /* ------ Procedures ------ */
133 
134 /* Build a function structure from a PostScript dictionary. */
135 int
136 fn_build_function(i_ctx_t *i_ctx_p, const ref * op, gs_function_t ** ppfn, gs_memory_t *mem)
137 {
138     return fn_build_sub_function(i_ctx_p, op, ppfn, 0, mem);
139 }
140 int
141 fn_build_sub_function(i_ctx_t *i_ctx_p, const ref * op, gs_function_t ** ppfn,
142 		      int depth, gs_memory_t *mem)
143 {
144     int code, type, i;
145     gs_function_params_t params;
146 
147     if (depth > MAX_SUB_FUNCTION_DEPTH)
148 	return_error(e_limitcheck);
149     check_type(*op, t_dictionary);
150     code = dict_int_param(op, "FunctionType", 0, max_int, -1, &type);
151     if (code < 0)
152 	return code;
153     for (i = 0; i < build_function_type_table_count; ++i)
154 	if (build_function_type_table[i].type == type)
155 	    break;
156     if (i == build_function_type_table_count)
157 	return_error(e_rangecheck);
158     /* Collect parameters common to all function types. */
159     params.Domain = 0;
160     params.Range = 0;
161     code = fn_build_float_array(op, "Domain", true, true, &params.Domain, mem);
162     if (code < 0)
163 	goto fail;
164     params.m = code >> 1;
165     code = fn_build_float_array(op, "Range", false, true, &params.Range, mem);
166     if (code < 0)
167 	goto fail;
168     params.n = code >> 1;
169     /* Finish building the function. */
170     /* If this fails, it will free all the parameters. */
171     return (*build_function_type_table[i].proc)
172 	(i_ctx_p, op, &params, depth + 1, ppfn, mem);
173 fail:
174     gs_free_const_object(mem, params.Range, "Range");
175     gs_free_const_object(mem, params.Domain, "Domain");
176     return code;
177 }
178 
179 /* Allocate an array of function objects. */
180 int
181 alloc_function_array(uint count, gs_function_t *** pFunctions,
182 		     gs_memory_t *mem)
183 {
184     gs_function_t **ptr;
185 
186     if (count == 0)
187 	return_error(e_rangecheck);
188     ptr = gs_alloc_struct_array(mem, count, gs_function_t *,
189 				&st_function_ptr_element, "Functions");
190     if (ptr == 0)
191 	return_error(e_VMerror);
192     memset(ptr, 0, sizeof(*ptr) * count);
193     *pFunctions = ptr;
194     return 0;
195 }
196 
197 /*
198  * Collect a heap-allocated array of floats.  If the key is missing, set
199  * *pparray = 0 and return 0; otherwise set *pparray and return the number
200  * of elements.  Note that 0-length arrays are acceptable, so if the value
201  * returned is 0, the caller must check whether *pparray == 0.
202  */
203 int
204 fn_build_float_array(const ref * op, const char *kstr, bool required,
205 		     bool even, const float **pparray, gs_memory_t *mem)
206 {
207     ref *par;
208     int code;
209 
210     *pparray = 0;
211     if (dict_find_string(op, kstr, &par) <= 0)
212 	return (required ? gs_note_error(e_rangecheck) : 0);
213     if (!r_is_array(par))
214 	return_error(e_typecheck);
215     {
216 	uint size = r_size(par);
217 	float *ptr = (float *)
218 	    gs_alloc_byte_array(mem, size, sizeof(float), kstr);
219 
220 	if (ptr == 0)
221 	    return_error(e_VMerror);
222 	code = dict_float_array_check_param(op, kstr, size, ptr, NULL,
223 					    0, e_rangecheck);
224 	if (code < 0 || (even && (code & 1) != 0)) {
225 	    gs_free_object(mem, ptr, kstr);
226 	    return(code < 0 ? code : gs_note_error(e_rangecheck));
227 	}
228 	*pparray = ptr;
229     }
230     return code;
231 }
232 
233 /*
234  * If a PostScript object is a Function procedure, return the function
235  * object, otherwise return 0.
236  */
237 gs_function_t *
238 ref_function(const ref *op)
239 {
240     if (r_has_type(op, t_array) &&
241 	r_has_masked_attrs(op, a_executable | a_execute,
242 			   a_executable | a_all) &&
243 	r_size(op) == 2 &&
244 	r_has_type_attrs(op->value.refs + 1, t_operator, a_executable) &&
245 	op->value.refs[1].value.opproc == zexecfunction &&
246 	r_is_struct(op->value.refs) &&
247 	r_has_masked_attrs(op->value.refs, a_executable | a_execute,
248 			   a_executable | a_all)
249 	)
250 	return (gs_function_t *)op->value.refs->value.pstruct;
251     return 0;
252 }
253 
254 /* ------ Initialization procedure ------ */
255 
256 const op_def zfunc_op_defs[] =
257 {
258     {"1.buildfunction", zbuildfunction},
259     {"1%execfunction", zexecfunction},
260     op_def_end(0)
261 };
262