Commit | Line | Data |
---|---|---|
f6912cbd WJ |
1 | /* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* zmisc.c */ | |
21 | /* Miscellaneous operators for Ghostscript */ | |
22 | #include "memory_.h" | |
23 | #include "string_.h" | |
24 | #include "ghost.h" | |
25 | #include "gp.h" | |
26 | #include "errors.h" | |
27 | #include "oper.h" | |
28 | #include "alloc.h" | |
29 | #include "dict.h" | |
30 | #include "dstack.h" /* for name lookup in bind */ | |
31 | #include "name.h" | |
32 | #include "packed.h" | |
33 | #include "store.h" | |
34 | #include "gxfixed.h" /* for gstype1.h */ | |
35 | #include "gstype1.h" | |
36 | ||
37 | /* Import the C getenv function */ | |
38 | extern char *getenv(P1(char *)); | |
39 | ||
40 | /* bind */ | |
41 | int | |
42 | zbind(register os_ptr op) | |
43 | { os_ptr bsp = op; /* bottom of stack */ | |
44 | ref *defp = op; | |
45 | switch ( r_type(op) ) | |
46 | { | |
47 | case t_array: | |
48 | case t_mixedarray: | |
49 | case t_shortarray: | |
50 | break; | |
51 | case t_oparray: | |
52 | defp = &op_array_table.value.refs[op_index(op) - op_def_count]; | |
53 | break; | |
54 | default: | |
55 | return e_typecheck; | |
56 | } | |
57 | ++bsp; | |
58 | /* We must not make the top-level procedure read-only, */ | |
59 | /* but we must bind it even if it is read-only already. */ | |
60 | *bsp = *defp; | |
61 | /* Here are the invariants for the following loop: */ | |
62 | /* op < bsp <= ostop; */ | |
63 | /* for every pointer p such that op < p <= bsp, */ | |
64 | /* *p is an array (or packedarray) ref. */ | |
65 | #define r_is_ex_oper(rp)\ | |
66 | ((r_btype(rp) == t_operator || r_type(rp) == t_oparray) &&\ | |
67 | r_has_attr(rp, a_executable)) | |
68 | while ( bsp > op ) | |
69 | { while ( r_size(bsp) ) | |
70 | { ref *tp = bsp->value.refs; | |
71 | r_inc_size(bsp, -1); | |
72 | if ( *(ushort *)tp > packed_max_full_ref ) | |
73 | { /* Check for a packed executable name */ | |
74 | ushort elt = *(ushort *)tp; | |
75 | if ( (elt & ~(ushort)packed_max_name_index) == | |
76 | pt_tag(pt_executable_name) ) | |
77 | { ref nref; | |
78 | ref *pvalue; | |
79 | name_index_ref(elt & packed_max_name_index, | |
80 | &nref); | |
81 | if ( (pvalue = dict_find_name(&nref)) != 0 && | |
82 | r_is_ex_oper(pvalue) | |
83 | ) | |
84 | /* Note: can't undo this by restore! */ | |
85 | *(ushort *)tp = | |
86 | pt_tag(pt_executable_operator) + | |
87 | op_index(pvalue); | |
88 | } | |
89 | bsp->value.refs = (ref *)((ushort *)tp + 1); | |
90 | } | |
91 | else | |
92 | switch ( bsp->value.refs++, r_type(tp) ) | |
93 | { | |
94 | case t_name: /* bind the name if an operator */ | |
95 | if ( r_has_attr(tp, a_executable) ) | |
96 | { ref *pvalue; | |
97 | if ( (pvalue = dict_find_name(tp)) != 0 && | |
98 | r_is_ex_oper(pvalue) | |
99 | ) | |
100 | ref_assign_old(tp, pvalue, "bind"); | |
101 | } | |
102 | break; | |
103 | case t_array: /* push into array if procedure */ | |
104 | if ( !r_has_attr(tp, a_write) ) break; | |
105 | case t_mixedarray: | |
106 | case t_shortarray: | |
107 | if ( r_has_attr(tp, a_executable) && bsp < ostop ) | |
108 | { /* Make reference read-only */ | |
109 | r_clear_attrs(tp, a_write); | |
110 | *++bsp = *tp; | |
111 | } | |
112 | } | |
113 | } | |
114 | bsp--; | |
115 | } | |
116 | return 0; | |
117 | } | |
118 | ||
119 | /* currenttime */ | |
120 | int | |
121 | zcurrenttime(register os_ptr op) | |
122 | { long date_time[2]; | |
123 | gp_get_clock(date_time); | |
124 | push(1); | |
125 | make_real(op, date_time[0] * 1440.0 + date_time[1] / 60000.0); | |
126 | return 0; | |
127 | } | |
128 | ||
129 | /* getenv */ | |
130 | int | |
131 | zgetenv(register os_ptr op) | |
132 | { char *str, *value; | |
133 | int code; | |
134 | check_read_type(*op, t_string); | |
135 | str = ref_to_string(op, "getenv name"); | |
136 | if ( str == 0 ) return e_VMerror; | |
137 | value = getenv(str); | |
138 | alloc_free(str, r_size(op) + 1, 1, "getenv name"); | |
139 | if ( value == 0 ) /* not found */ | |
140 | { make_bool(op, 0); | |
141 | return 0; | |
142 | } | |
143 | code = string_to_ref(value, op, "getenv value"); | |
144 | if ( code < 0 ) return code; | |
145 | push(1); | |
146 | make_bool(op, 1); | |
147 | return 0; | |
148 | } | |
149 | ||
150 | /* makeoperator */ | |
151 | int | |
152 | zmakeoperator(register os_ptr op) | |
153 | { check_type(op[-1], t_name); | |
154 | check_proc(*op); | |
155 | if ( op_array_count == r_size(&op_array_table) ) | |
156 | return e_limitcheck; | |
157 | ref_assign_old(&op_array_table.value.refs[op_array_count], | |
158 | op, "makeoperator"); | |
159 | op_array_nx_table[op_array_count] = name_index(op - 1); | |
160 | r_set_type_attrs(op - 1, t_oparray, a_executable); | |
161 | r_set_size(op - 1, op_def_count + op_array_count); | |
162 | op_array_count++; | |
163 | pop(1); | |
164 | return 0; | |
165 | } | |
166 | ||
167 | /* setdebug */ | |
168 | int | |
169 | zsetdebug(register os_ptr op) | |
170 | { check_read_type(op[-1], t_string); | |
171 | check_type(*op, t_boolean); | |
172 | #ifdef DEBUG | |
173 | { int i; | |
174 | for ( i = 0; i < r_size(op - 1); i++ ) | |
175 | gs_debug[op[-1].value.bytes[i] & 127] = | |
176 | op->value.index; | |
177 | } | |
178 | #endif | |
179 | pop(2); | |
180 | return 0; | |
181 | } | |
182 | ||
183 | /* type1encrypt, type1decrypt */ | |
184 | private int type1crypt(P2(os_ptr, | |
185 | int (*)(P4(byte *, byte *, uint, ushort *)))); | |
186 | int | |
187 | ztype1encrypt(os_ptr op) | |
188 | { return type1crypt(op, gs_type1_encrypt); | |
189 | } | |
190 | int | |
191 | ztype1decrypt(os_ptr op) | |
192 | { return type1crypt(op, gs_type1_decrypt); | |
193 | } | |
194 | private int | |
195 | type1crypt(register os_ptr op, int (*proc)(P4(byte *, byte *, uint, ushort *))) | |
196 | { crypt_state state; | |
197 | uint ssize; | |
198 | check_type(op[-2], t_integer); | |
199 | state = op[-2].value.intval; | |
200 | if ( op[-2].value.intval != state ) | |
201 | return e_rangecheck; /* state value was truncated */ | |
202 | check_read_type(op[-1], t_string); | |
203 | check_write_type(*op, t_string); | |
204 | ssize = r_size(op - 1); | |
205 | if ( r_size(op) < ssize ) | |
206 | return e_rangecheck; | |
207 | (void) (*proc)(op->value.bytes, op[-1].value.bytes, ssize, | |
208 | &state); /* can't fail */ | |
209 | op[-2].value.intval = state; | |
210 | op[-1] = *op; | |
211 | r_set_size(op - 1, ssize); | |
212 | pop(1); | |
213 | return 0; | |
214 | } | |
215 | ||
216 | /* usertime */ | |
217 | int | |
218 | zusertime(register os_ptr op) | |
219 | { long date_time[2]; | |
220 | gp_get_clock(date_time); | |
221 | push(1); | |
222 | make_int(op, date_time[0] * 86400000L + date_time[1]); | |
223 | return 0; | |
224 | } | |
225 | ||
226 | /* ------ Initialization procedure ------ */ | |
227 | ||
228 | op_def zmisc_op_defs[] = { | |
229 | {"1bind", zbind}, | |
230 | {"0currenttime", zcurrenttime}, | |
231 | {"1getenv", zgetenv}, | |
232 | {"2makeoperator", zmakeoperator}, | |
233 | {"2setdebug", zsetdebug}, | |
234 | {"3type1encrypt", ztype1encrypt}, | |
235 | {"3type1decrypt", ztype1decrypt}, | |
236 | {"0usertime", zusertime}, | |
237 | op_def_end(0) | |
238 | }; |