/src/ghostpdl/psi/zdscpars.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* C language interface routines to DSC parser */ |
18 | | |
19 | | /* |
20 | | * The DSC parser consists of three pieces. The first piece is a DSC parser |
21 | | * which was coded by Russell Lang (dscparse.c and dscparse.h). The second |
22 | | * piece is this module. These two are sufficient to parse DSC comments |
23 | | * and make them available to a client written in PostScript. The third |
24 | | * piece is a PostScript language module (gs_dscp.ps) that uses certain |
25 | | * comments to affect the interpretation of the file. |
26 | | * |
27 | | * The .initialize_dsc_parser operator defined in this file creates an |
28 | | * instance of Russell's parser, and puts it in a client-supplied dictionary |
29 | | * under a known name (/DSC_struct). |
30 | | * |
31 | | * When the PostScript scanner sees a possible DSC comment (first characters |
32 | | * in a line are %%), it calls the procedure that is the value of the user |
33 | | * parameter ProcessDSCComments. This procedure should loads the dictionary |
34 | | * that was passed to .initialize_dsc_parser, and then call the |
35 | | * .parse_dsc_comments operator defined in this file. |
36 | | * |
37 | | * These two operators comprise the interface between PostScript and C code. |
38 | | * |
39 | | * There is a "feature" named usedsc that loads a PostScript file |
40 | | * (gs_dscp.ps), which installs a simple framework for processing DSC |
41 | | * comments and having them affect interpretation of the file (e.g., by |
42 | | * setting page device parameters). See gs_dscp.ps for more information. |
43 | | * |
44 | | * .parse_dsc_comments pulls the comment string off of the stack and passes |
45 | | * it to Russell's parser. That parser parses the comment and puts any |
46 | | * parameter values into a DSC structure. That parser also returns a code |
47 | | * which indicates which type of comment was found. .parse_dsc_comments |
48 | | * looks at the return code and transfers any interesting parameters from |
49 | | * the DSC structure into key value pairs in the dsc_dict dictionary. It |
50 | | * also translates the comment type code into a key name (comment name). |
51 | | * The key name is placed on the operand stack. Control then returns to |
52 | | * PostScript code, which can pull the key name from the operand stack and |
53 | | * use it to determine what further processing needs to be done at the PS |
54 | | * language level. |
55 | | * |
56 | | * To add support for new DSC comments: |
57 | | * |
58 | | * 1. Verify that Russell's parser supports the comment. If not, then add |
59 | | * the required support. |
60 | | * |
61 | | * 2. Add an entry into DSCcmdlist. This table contains three values for |
62 | | * each command that we support. The first is Russell's return code for |
63 | | * the command. The second is the key name that we pass back on the |
64 | | * operand stack. (Thus this table translates Russell's codes into key |
65 | | * names for the PostScript client.) The third entry is a pointer to a |
66 | | * local function for transferring values from Russell's DSC structure |
67 | | * into key/value pairs in dsc_dict. |
68 | | * |
69 | | * 3. Create the local function described at the end of the last item. |
70 | | * There are some support routines like dsc_put_integer() and |
71 | | * dsc_put_string() to help implement these functions. |
72 | | * |
73 | | * 4. If the usedsc feature should recognize and process the new comments, |
74 | | * add a processing routine into the dictionary DSCparserprocs in |
75 | | * gs_dscp.ps. The keys in this dictionary are the key names described |
76 | | * in item 2 above. |
77 | | */ |
78 | | |
79 | | #include "ghost.h" |
80 | | #include "string_.h" |
81 | | #include "memory_.h" |
82 | | #include "gsstruct.h" |
83 | | #include "ialloc.h" |
84 | | #include "iname.h" |
85 | | #include "istack.h" /* for iparam.h */ |
86 | | #include "iparam.h" |
87 | | #include "ivmspace.h" |
88 | | #include "oper.h" |
89 | | #include "estack.h" |
90 | | #include "store.h" |
91 | | #include "idict.h" |
92 | | #include "iddict.h" |
93 | | #include "dscparse.h" |
94 | | |
95 | | /* |
96 | | * Declare the structure we use to represent an instance of the parser |
97 | | * as a t_struct. Currently it just saves a pointer to Russell's |
98 | | * data structure. |
99 | | */ |
100 | | typedef struct dsc_data_s { |
101 | | CDSC *dsc_data_ptr; |
102 | | int document_level; |
103 | | } dsc_data_t; |
104 | | |
105 | | /* Structure descriptors */ |
106 | | static void dsc_finalize(const gs_memory_t *cmem, void *vptr); |
107 | | gs_private_st_simple_final(st_dsc_data_t, dsc_data_t, "dsc_data_struct", dsc_finalize); |
108 | | |
109 | | static void *zDSC_memalloc (size_t size, void *closure_data); |
110 | | static void zDSC_memfree(void *ptr, void *closure_data); |
111 | | |
112 | | |
113 | | /* Define the key name for storing the instance pointer in a dictionary. */ |
114 | | static const char * const dsc_dict_name = "DSC_struct"; |
115 | | |
116 | | /* ---------------- Initialization / finalization ---------------- */ |
117 | | |
118 | | /* |
119 | | * If we return CDSC_OK then Russell's parser will make it best guess when |
120 | | * it encounters unexpected comment situations. |
121 | | */ |
122 | | static int |
123 | | dsc_error_handler(void *caller_data, CDSC *dsc, unsigned int explanation, |
124 | | const char *line, unsigned int line_len) |
125 | 9.00k | { |
126 | 9.00k | return CDSC_OK; |
127 | 9.00k | } |
128 | | |
129 | | static void *zDSC_memalloc (size_t size, void *closure_data) |
130 | 652k | { |
131 | 652k | gs_memory_t *cmem = (gs_memory_t *)closure_data; |
132 | | |
133 | 652k | return(gs_alloc_bytes(cmem, size, "zDSC_memalloc: DSC parsing memory alloc")); |
134 | 652k | } |
135 | | |
136 | | static void zDSC_memfree(void *ptr, void *closure_data) |
137 | 652k | { |
138 | 652k | gs_memory_t *cmem = (gs_memory_t *)closure_data; |
139 | | |
140 | 652k | gs_free_object(cmem, ptr, "zDSC_memfree: DSC parsing memory free"); |
141 | 652k | } |
142 | | |
143 | | /* |
144 | | * This operator creates a new, initialized instance of the DSC parser. |
145 | | */ |
146 | | /* <dict> .initialize_dsc_parser - */ |
147 | | static int |
148 | | zinitialize_dsc_parser(i_ctx_t *i_ctx_p) |
149 | 162k | { |
150 | 162k | ref local_ref; |
151 | 162k | int code; |
152 | 162k | os_ptr const op = osp; |
153 | 162k | dict *pdict; |
154 | 162k | gs_memory_t *mem; |
155 | 162k | dsc_data_t *data; |
156 | | |
157 | 162k | if (ref_stack_count(&o_stack) < 1) |
158 | 0 | return_error(gs_error_stackunderflow); |
159 | | |
160 | 162k | check_read_type(*op, t_dictionary); |
161 | | |
162 | 162k | pdict = op->value.pdict; |
163 | 162k | mem = (gs_memory_t *)dict_memory(pdict); |
164 | | |
165 | 162k | data = gs_alloc_struct(mem, dsc_data_t, &st_dsc_data_t, "DSC parser init"); |
166 | 162k | if (!data) |
167 | 0 | return_error(gs_error_VMerror); |
168 | 162k | data->document_level = 0; |
169 | | |
170 | 162k | data->dsc_data_ptr = dsc_init_with_alloc((void *) "Ghostscript DSC parsing", |
171 | 162k | zDSC_memalloc, zDSC_memfree, (void *)mem->non_gc_memory); |
172 | 162k | if (!data->dsc_data_ptr) |
173 | 0 | return_error(gs_error_VMerror); |
174 | 162k | dsc_set_error_function(data->dsc_data_ptr, dsc_error_handler); |
175 | 162k | make_astruct(&local_ref, a_readonly | r_space(op), (byte *) data); |
176 | 162k | code = idict_put_string(op, dsc_dict_name, &local_ref); |
177 | 162k | if (code >= 0) |
178 | 162k | pop(1); |
179 | 162k | return code; |
180 | 162k | } |
181 | | |
182 | | /* |
183 | | * This routine will free the memory associated with Russell's parser. |
184 | | */ |
185 | | static void |
186 | | dsc_finalize(const gs_memory_t *cmem, void *vptr) |
187 | 162k | { |
188 | 162k | dsc_data_t * const st = vptr; |
189 | 162k | (void)cmem; /* unused */ |
190 | | |
191 | 162k | if (st->dsc_data_ptr) |
192 | 162k | dsc_free(st->dsc_data_ptr); |
193 | 162k | st->dsc_data_ptr = NULL; |
194 | 162k | } |
195 | | |
196 | | /* ---------------- Parsing ---------------- */ |
197 | | |
198 | | /* ------ Utilities for returning values ------ */ |
199 | | |
200 | | /* Return an integer value. */ |
201 | | static int |
202 | | dsc_put_int(gs_param_list *plist, const char *keyname, int value) |
203 | 8.57k | { |
204 | 8.57k | return param_write_int(plist, keyname, &value); |
205 | 8.57k | } |
206 | | |
207 | | /* Return a string value. */ |
208 | | static int |
209 | | dsc_put_string(gs_param_list *plist, const char *keyname, |
210 | | const char *string) |
211 | 49.9k | { |
212 | 49.9k | gs_param_string str; |
213 | | |
214 | 49.9k | param_string_from_transient_string(str, string); |
215 | 49.9k | return param_write_string(plist, keyname, &str); |
216 | 49.9k | } |
217 | | |
218 | | /* Return a BoundingBox value. */ |
219 | | static int |
220 | | dsc_put_bounding_box(gs_param_list *plist, const char *keyname, |
221 | | const CDSCBBOX *pbbox) |
222 | 9.37k | { |
223 | | /* pbbox is NULL iff the bounding box values was "(atend)". */ |
224 | 9.37k | int values[4]; |
225 | 9.37k | gs_param_int_array va; |
226 | | |
227 | 9.37k | if (!pbbox) |
228 | 768 | return 0; |
229 | 8.60k | values[0] = pbbox->llx; |
230 | 8.60k | values[1] = pbbox->lly; |
231 | 8.60k | values[2] = pbbox->urx; |
232 | 8.60k | values[3] = pbbox->ury; |
233 | 8.60k | va.data = values; |
234 | 8.60k | va.size = 4; |
235 | 8.60k | va.persistent = false; |
236 | 8.60k | return param_write_int_array(plist, keyname, &va); |
237 | 9.37k | } |
238 | | |
239 | | /* ------ Return values for individual comment types ------ */ |
240 | | |
241 | | /* |
242 | | * These routines transfer data from the C structure into Postscript |
243 | | * key/value pairs in a dictionary. |
244 | | */ |
245 | | static int |
246 | | dsc_adobe_header(gs_param_list *plist, const CDSC *pData) |
247 | 5.34k | { |
248 | 5.34k | return dsc_put_int(plist, "EPSF", (int)(pData->epsf? 1: 0)); |
249 | 5.34k | } |
250 | | |
251 | | static int |
252 | | dsc_creator(gs_param_list *plist, const CDSC *pData) |
253 | 21.9k | { |
254 | 21.9k | return dsc_put_string(plist, "Creator", pData->dsc_creator ); |
255 | 21.9k | } |
256 | | |
257 | | static int |
258 | | dsc_creation_date(gs_param_list *plist, const CDSC *pData) |
259 | 7.47k | { |
260 | 7.47k | return dsc_put_string(plist, "CreationDate", pData->dsc_date ); |
261 | 7.47k | } |
262 | | |
263 | | static int |
264 | | dsc_title(gs_param_list *plist, const CDSC *pData) |
265 | 18.3k | { |
266 | 18.3k | return dsc_put_string(plist, "Title", pData->dsc_title ); |
267 | 18.3k | } |
268 | | |
269 | | static int |
270 | | dsc_for(gs_param_list *plist, const CDSC *pData) |
271 | 2.17k | { |
272 | 2.17k | return dsc_put_string(plist, "For", pData->dsc_for); |
273 | 2.17k | } |
274 | | |
275 | | static int |
276 | | dsc_bounding_box(gs_param_list *plist, const CDSC *pData) |
277 | 9.36k | { |
278 | 9.36k | return dsc_put_bounding_box(plist, "BoundingBox", pData->bbox); |
279 | 9.36k | } |
280 | | |
281 | | static int |
282 | | dsc_page(gs_param_list *plist, const CDSC *pData) |
283 | 1.72k | { |
284 | 1.72k | int page_num = pData->page_count; |
285 | | |
286 | 1.72k | if (page_num) /* If we have page information */ |
287 | 1.02k | return dsc_put_int(plist, "PageNum", |
288 | 1.02k | pData->page[page_num - 1].ordinal ); |
289 | 699 | else /* No page info - so return page=0 */ |
290 | 699 | return dsc_put_int(plist, "PageNum", 0 ); |
291 | 1.72k | } |
292 | | |
293 | | static int |
294 | | dsc_pages(gs_param_list *plist, const CDSC *pData) |
295 | 1.49k | { |
296 | 1.49k | return dsc_put_int(plist, "NumPages", pData->page_pages); |
297 | 1.49k | } |
298 | | |
299 | | static int |
300 | | dsc_page_bounding_box(gs_param_list *plist, const CDSC *pData) |
301 | 3 | { |
302 | 3 | return dsc_put_bounding_box(plist, "PageBoundingBox", pData->page_bbox); |
303 | 3 | } |
304 | | |
305 | | /* |
306 | | * Translate Russell's defintions of orientation into Postscript's. |
307 | | */ |
308 | | static int |
309 | | convert_orient(CDSC_ORIENTATION_ENUM orient) |
310 | 0 | { |
311 | 0 | switch (orient) { |
312 | 0 | case CDSC_PORTRAIT: return 0; |
313 | 0 | case CDSC_LANDSCAPE: return 1; |
314 | 0 | case CDSC_UPSIDEDOWN: return 2; |
315 | 0 | case CDSC_SEASCAPE: return 3; |
316 | 0 | default: return -1; |
317 | 0 | } |
318 | 0 | } |
319 | | |
320 | | static int |
321 | | dsc_page_orientation(gs_param_list *plist, const CDSC *pData) |
322 | 0 | { |
323 | 0 | int page_num = pData->page_count; |
324 | | |
325 | | /* |
326 | | * The PageOrientation comment might be either in the 'defaults' |
327 | | * section or in a page section. If in the defaults then fhe value |
328 | | * will be in page_orientation. |
329 | | */ |
330 | 0 | if (page_num && pData->page[page_num - 1].orientation != CDSC_ORIENT_UNKNOWN) |
331 | 0 | return dsc_put_int(plist, "PageOrientation", |
332 | 0 | convert_orient(pData->page[page_num - 1].orientation)); |
333 | 0 | else |
334 | 0 | return dsc_put_int(plist, "Orientation", |
335 | 0 | convert_orient(pData->page_orientation)); |
336 | 0 | } |
337 | | |
338 | | static int |
339 | | dsc_orientation(gs_param_list *plist, const CDSC *pData) |
340 | 0 | { |
341 | 0 | return dsc_put_int(plist, "Orientation", |
342 | 0 | convert_orient(pData->page_orientation)); |
343 | 0 | } |
344 | | |
345 | | static int |
346 | | dsc_viewing_orientation(gs_param_list *plist, const CDSC *pData) |
347 | 0 | { |
348 | 0 | int page_num = pData->page_count; |
349 | 0 | const char *key; |
350 | 0 | const CDSCCTM *pctm; |
351 | 0 | float values[4]; |
352 | 0 | gs_param_float_array va; |
353 | | |
354 | | /* |
355 | | * As for PageOrientation, ViewingOrientation may be either in the |
356 | | * 'defaults' section or in a page section. |
357 | | */ |
358 | 0 | if (page_num && pData->page[page_num - 1].viewing_orientation != NULL) { |
359 | 0 | key = "PageViewingOrientation"; |
360 | 0 | pctm = pData->page[page_num - 1].viewing_orientation; |
361 | 0 | } else if (pData->viewing_orientation) { |
362 | 0 | key = "ViewingOrientation"; |
363 | 0 | pctm = pData->viewing_orientation; |
364 | 0 | } else |
365 | 0 | return 0; /* ignore broken comment */ |
366 | 0 | values[0] = pctm->xx; |
367 | 0 | values[1] = pctm->xy; |
368 | 0 | values[2] = pctm->yx; |
369 | 0 | values[3] = pctm->yy; |
370 | 0 | va.data = values; |
371 | 0 | va.size = 4; |
372 | 0 | va.persistent = false; |
373 | 0 | return param_write_float_array(plist, key, &va); |
374 | 0 | } |
375 | | |
376 | | /* |
377 | | * This list is used to translate the commment code returned |
378 | | * from Russell's DSC parser, define a name, and a parameter procedure. |
379 | | */ |
380 | | typedef struct cmdlist_s { |
381 | | int code; /* Russell's DSC parser code (see dsc.h) */ |
382 | | const char *comment_name; /* A name to be returned to postscript caller */ |
383 | | int (*dsc_proc) (gs_param_list *, const CDSC *); |
384 | | /* A routine for transferring parameter values |
385 | | from C data structure to postscript dictionary |
386 | | key/value pairs. */ |
387 | | } cmdlist_t; |
388 | | |
389 | | static const cmdlist_t DSCcmdlist[] = { |
390 | | { CDSC_PSADOBE, "Header", dsc_adobe_header }, |
391 | | { CDSC_CREATOR, "Creator", dsc_creator }, |
392 | | { CDSC_CREATIONDATE, "CreationDate", dsc_creation_date }, |
393 | | { CDSC_TITLE, "Title", dsc_title }, |
394 | | { CDSC_FOR, "For", dsc_for }, |
395 | | { CDSC_BOUNDINGBOX, "BoundingBox", dsc_bounding_box }, |
396 | | { CDSC_ORIENTATION, "Orientation", dsc_orientation }, |
397 | | { CDSC_BEGINDEFAULTS, "BeginDefaults", NULL }, |
398 | | { CDSC_ENDDEFAULTS, "EndDefaults", NULL }, |
399 | | { CDSC_PAGE, "Page", dsc_page }, |
400 | | { CDSC_PAGES, "Pages", dsc_pages }, |
401 | | { CDSC_PAGEORIENTATION, "PageOrientation", dsc_page_orientation }, |
402 | | { CDSC_PAGEBOUNDINGBOX, "PageBoundingBox", dsc_page_bounding_box }, |
403 | | { CDSC_VIEWINGORIENTATION, "ViewingOrientation", dsc_viewing_orientation }, |
404 | | { CDSC_EOF, "EOF", NULL }, |
405 | | { 0, "NOP", NULL } /* Table terminator */ |
406 | | }; |
407 | | |
408 | | /* ------ Parser interface ------ */ |
409 | | |
410 | | /* |
411 | | * There are a few comments that we do not want to send to Russell's |
412 | | * DSC parser. If we send the data block type comments, Russell's |
413 | | * parser will want to skip the specified block of data. This is not |
414 | | * appropriate for our situation. So we use this list to check for this |
415 | | * type of comment and do not send it to Russell's parser if found. |
416 | | */ |
417 | | static const char * const BadCmdlist[] = { |
418 | | "%%BeginData:", |
419 | | "%%EndData", |
420 | | "%%BeginBinary:", |
421 | | "%%EndBinary", |
422 | | NULL /* List terminator */ |
423 | | }; |
424 | | |
425 | | /* See comments at start of module for description. */ |
426 | | /* <dict> <string> .parse_dsc_comments <dict> <dsc code> */ |
427 | | static int |
428 | | zparse_dsc_comments(i_ctx_t *i_ctx_p) |
429 | 1.49M | { |
430 | 1.49M | #define MAX_DSC_MSG_SIZE (DSC_LINE_LENGTH + 4) /* Allow for %% and CR/LF */ |
431 | 1.49M | os_ptr op = osp; |
432 | 1.49M | os_ptr const opString = op; |
433 | 1.49M | os_ptr const opDict = opString - 1; |
434 | 1.49M | uint ssize; |
435 | 1.49M | int comment_code, code; |
436 | 1.49M | char dsc_buffer[MAX_DSC_MSG_SIZE + 2]; |
437 | 1.49M | const cmdlist_t *pCmdList = DSCcmdlist; |
438 | 1.49M | const char * const *pBadList = BadCmdlist; |
439 | 1.49M | ref * pvalue; |
440 | 1.49M | dsc_data_t * dsc_state = NULL; |
441 | 1.49M | dict_param_list list; |
442 | | |
443 | 1.49M | check_op(2); |
444 | | /* |
445 | | * Verify operand types and length of DSC comment string. If a comment |
446 | | * is too long then we simply truncate it. Russell's parser gets to |
447 | | * handle any errors that may result. (Crude handling but the comment |
448 | | * is bad, so ...). |
449 | | */ |
450 | 1.49M | check_type(*opString, t_string); |
451 | 1.49M | check_type(*opDict, t_dictionary); |
452 | 1.49M | check_dict_write(*opDict); |
453 | 1.49M | ssize = r_size(opString); |
454 | 1.49M | if (ssize > MAX_DSC_MSG_SIZE) /* need room for EOL + \0 */ |
455 | 1.40k | ssize = MAX_DSC_MSG_SIZE; |
456 | | /* |
457 | | * Retrieve our state. |
458 | | */ |
459 | 1.49M | code = dict_find_string(opDict, dsc_dict_name, &pvalue); |
460 | 1.49M | if (code < 0) |
461 | 0 | return code; |
462 | 1.49M | if (code == 0) |
463 | 0 | return_error(gs_error_undefined); |
464 | | |
465 | 1.49M | check_stype(*pvalue, st_dsc_data_t); |
466 | 1.49M | dsc_state = r_ptr(pvalue, dsc_data_t); |
467 | | /* |
468 | | * Pick up the comment string to be parsed. |
469 | | */ |
470 | 1.49M | memcpy(dsc_buffer, opString->value.bytes, ssize); |
471 | 1.49M | dsc_buffer[ssize] = 0x0d; /* Russell wants a 'line end' */ |
472 | 1.49M | dsc_buffer[ssize + 1] = 0; /* Terminate string */ |
473 | | /* |
474 | | * Skip data block comments (see comments in front of BadCmdList). |
475 | | */ |
476 | 7.47M | while (*pBadList && strncmp(*pBadList, dsc_buffer, strlen(*pBadList))) |
477 | 5.97M | pBadList++; |
478 | 1.49M | if (*pBadList) { /* If found in list, then skip comment */ |
479 | 1.04k | comment_code = 0; /* Ignore */ |
480 | 1.04k | if (dsc_buffer[2] == 'B') { |
481 | 656 | dsc_state->document_level++; |
482 | 656 | } else if (dsc_state->document_level > 0) { |
483 | 6 | dsc_state->document_level--; |
484 | 6 | } |
485 | 1.04k | } |
486 | 1.49M | else if (dsc_state->document_level > 0) { |
487 | 1.73k | comment_code = 0; /* Ignore */ |
488 | 1.49M | } else { |
489 | | /* |
490 | | * Parse comments - use Russell Lang's DSC parser. We need to get |
491 | | * data area for Russell Lang's parser. Note: We have saved the |
492 | | * location of the data area for the parser in our DSC dict. |
493 | | */ |
494 | 1.49M | comment_code = dsc_scan_data(dsc_state->dsc_data_ptr, dsc_buffer, ssize + 1); |
495 | 1.49M | if_debug1m('%', imemory, "[%%].parse_dsc_comments: code = %d\n", comment_code); |
496 | | /* |
497 | | * We ignore any errors from Russell's parser. The only value that |
498 | | * it will return for an error is -1 so there is very little information. |
499 | | * We also do not want bad DSC comments to abort processing of an |
500 | | * otherwise valid PS file. |
501 | | */ |
502 | 1.49M | if (comment_code < 0) |
503 | 0 | comment_code = 0; |
504 | 1.49M | } |
505 | | /* |
506 | | * Transfer data from DSC structure to postscript variables. |
507 | | * Look up proper handler in the local cmd decode list. |
508 | | */ |
509 | 23.0M | while (pCmdList->code && pCmdList->code != comment_code ) |
510 | 21.5M | pCmdList++; |
511 | 1.49M | if (pCmdList->dsc_proc) { |
512 | 67.9k | code = dict_param_list_write(&list, opDict, NULL, iimemory); |
513 | 67.9k | if (code < 0) |
514 | 0 | return code; |
515 | 67.9k | code = (pCmdList->dsc_proc)((gs_param_list *)&list, dsc_state->dsc_data_ptr); |
516 | 67.9k | iparam_list_release(&list); |
517 | 67.9k | if (code < 0) |
518 | 0 | return code; |
519 | 67.9k | } |
520 | | |
521 | | /* Put DSC comment name onto operand stack (replace string). */ |
522 | | |
523 | 1.49M | return name_enter_string(imemory, pCmdList->comment_name, opString); |
524 | 1.49M | } |
525 | | |
526 | | /* ------ Initialization procedure ------ */ |
527 | | |
528 | | const op_def zdscpars_op_defs[] = { |
529 | | {"1.initialize_dsc_parser", zinitialize_dsc_parser}, |
530 | | {"2.parse_dsc_comments", zparse_dsc_comments}, |
531 | | op_def_end(0) |
532 | | }; |