Coverage Report

Created: 2022-04-16 11:23

/src/ghostpdl/base/gscparam.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* Default implementation of parameter lists */
18
#include "memory_.h"
19
#include "string_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsparam.h"
23
#include "gsstruct.h"
24
25
/* Forward references */
26
typedef union c_param_value_s {
27
    GS_PARAM_VALUE_UNION(gs_c_param_list);
28
} gs_c_param_value;
29
/*typedef struct gs_c_param_s gs_c_param; *//* in gsparam.h */
30
31
/* Define the GC type for a parameter list. */
32
private_st_c_param_list();
33
34
/* Lengths corresponding to various gs_param_type_xxx types */
35
const byte gs_param_type_sizes[] = {
36
    GS_PARAM_TYPE_SIZES(sizeof(gs_c_param_list))
37
};
38
39
/* Lengths of *actual* data-containing type pointed to or contained by gs_param_type_xxx's */
40
const byte gs_param_type_base_sizes[] = {
41
    GS_PARAM_TYPE_BASE_SIZES(0)
42
};
43
44
/*
45
 * Define a parameter list element.  We use gs_param_type_any to identify
46
 * elements that have been requested but not yet written.  The reading
47
 * procedures must recognize such elements as undefined, and ignore them.
48
 */
49
struct gs_c_param_s {
50
    gs_c_param *next;
51
    gs_param_key_t key;
52
    bool free_key;
53
    gs_c_param_value value;
54
    gs_param_type type;
55
    void *alternate_typed_data;
56
    int error;
57
};
58
59
/* GC descriptor and procedures */
60
gs_private_st_composite(st_c_param, gs_c_param, "gs_c_param",
61
                        c_param_enum_ptrs, c_param_reloc_ptrs);
62
0
ENUM_PTRS_WITH(c_param_enum_ptrs, gs_c_param *param) {
63
0
    index -= 3;
64
0
    switch (param->type) {
65
        /* Only the aggregate types are handled specially. */
66
0
    case gs_param_type_dict:
67
0
    case gs_param_type_dict_int_keys:
68
0
    case gs_param_type_array:
69
0
        return ENUM_USING(st_c_param_list, &param->value.d,
70
0
                          sizeof(param->value.d), index);
71
0
    default: {
72
0
        gs_param_typed_value value;
73
74
0
        value.value = *(const gs_param_value *)&param->value;
75
0
        value.type = param->type;
76
0
        return gs_param_typed_value_enum_ptrs(mem, &value, sizeof(value), index,
77
0
                                              pep, NULL, gcst);
78
0
    }
79
0
    }
80
0
}
81
0
case 0: return ENUM_OBJ(param->next);
82
0
case 1: return ENUM_OBJ(param->alternate_typed_data);
83
0
case 2:
84
0
    if (!param->key.persistent) {
85
0
        gs_const_string key;
86
87
0
        key.data = param->key.data;
88
0
        key.size = param->key.size;
89
0
        return ENUM_STRING(&key);
90
0
    } else
91
0
        return ENUM_OBJ(0);  /* keep going */
92
0
ENUM_PTRS_END
93
0
RELOC_PTRS_WITH(c_param_reloc_ptrs, gs_c_param *param) {
94
0
    RELOC_VAR(param->next);
95
0
    RELOC_VAR(param->alternate_typed_data);
96
0
    if (!param->key.persistent) {
97
0
        gs_const_string key;
98
99
0
        key.data = param->key.data;
100
0
        key.size = param->key.size;
101
0
        RELOC_CONST_STRING_VAR(key);
102
0
        param->key.data = key.data;
103
0
    }
104
0
    switch (param->type) {
105
        /* Only the aggregate types are handled specially. */
106
0
    case gs_param_type_dict:
107
0
    case gs_param_type_dict_int_keys:
108
0
    case gs_param_type_array:
109
0
        RELOC_USING(st_c_param_list, &param->value.d, sizeof(param->value.d));
110
0
        break;
111
0
    default: {
112
0
        gs_param_typed_value value;
113
114
0
        value.value = *(gs_param_value *)&param->value;
115
0
        value.type = param->type;
116
0
        gs_param_typed_value_reloc_ptrs(&value, sizeof(value), NULL, gcst);
117
0
        *(gs_param_value *)&param->value = value.value;
118
0
    }
119
0
    }
120
0
}
121
0
RELOC_PTRS_END
122
123
/* ---------------- Utilities ---------------- */
124
125
gs_c_param_list *
126
gs_c_param_list_alloc(gs_memory_t *mem, client_name_t cname)
127
0
{
128
0
    return gs_alloc_struct(mem, gs_c_param_list, &st_c_param_list, cname);
129
0
}
130
131
static gs_c_param *
132
c_param_find(const gs_c_param_list *plist, gs_param_name pkey, bool any)
133
7.38k
{
134
7.38k
    gs_c_param *pparam = plist->head;
135
7.38k
    uint len = strlen(pkey);
136
137
14.7k
    for (; pparam != 0; pparam = pparam->next)
138
7.38k
        if (pparam->key.size == len && !memcmp(pparam->key.data, pkey, len))
139
0
            return (pparam->type != gs_param_type_any || any ? pparam : 0);
140
7.38k
    return 0;
141
7.38k
}
142
143
/* ---------------- Writing parameters to a list ---------------- */
144
145
static param_proc_begin_xmit_collection(c_param_begin_write_collection);
146
static param_proc_end_xmit_collection(c_param_end_write_collection);
147
static param_proc_xmit_typed(c_param_write_typed);
148
static param_proc_request(c_param_request);
149
static param_proc_requested(c_param_requested);
150
static const gs_param_list_procs c_write_procs =
151
{
152
    c_param_write_typed,
153
    c_param_begin_write_collection,
154
    c_param_end_write_collection,
155
    NULL,     /* get_next_key */
156
    c_param_request,
157
    c_param_requested
158
};
159
160
/* Initialize a list for writing. */
161
void
162
gs_c_param_list_write(gs_c_param_list * plist, gs_memory_t * mem)
163
21.5k
{
164
21.5k
    plist->memory = mem;
165
21.5k
    plist->head = 0;
166
21.5k
    plist->target = 0;    /* not used for writing */
167
21.5k
    plist->count = 0;
168
21.5k
    plist->any_requested = false;
169
21.5k
    plist->persistent_keys = true;
170
21.5k
    gs_c_param_list_write_more(plist);
171
21.5k
}
172
173
/* Set the target of a list.  Only relevant for reading. */
174
void
175
gs_c_param_list_set_target(gs_c_param_list *plist, gs_param_list *target)
176
0
{
177
0
    plist->target = target;
178
0
}
179
180
/* Re-enable a list for writing, without clearing it. */
181
/* gs_c_param_list_write must have been called previously. */
182
void
183
gs_c_param_list_write_more(gs_c_param_list * plist)
184
21.6k
{
185
21.6k
    plist->procs = &c_write_procs;
186
21.6k
    plist->coll_type = gs_param_collection_dict_any;
187
21.6k
}
188
189
/* Release a list. */
190
void
191
gs_c_param_list_release(gs_c_param_list * plist)
192
22.2k
{
193
22.2k
    gs_memory_t *mem = plist->memory;
194
22.2k
    gs_c_param *pparam;
195
196
22.2k
    while ((pparam = plist->head) != 0) {
197
41
        gs_c_param *next = pparam->next;
198
199
41
        switch (pparam->type) {
200
0
            case gs_param_type_dict:
201
0
            case gs_param_type_dict_int_keys:
202
0
            case gs_param_type_array:
203
0
                gs_c_param_list_release(&pparam->value.d);
204
0
                break;
205
41
            case gs_param_type_string:
206
41
            case gs_param_type_name:
207
41
            case gs_param_type_int_array:
208
41
            case gs_param_type_float_array:
209
41
            case gs_param_type_string_array:
210
41
            case gs_param_type_name_array:
211
41
                if (!pparam->value.s.persistent)
212
41
                    gs_free_const_object(mem, pparam->value.s.data,
213
41
                                         "gs_c_param_list_release data");
214
41
                break;
215
0
            default:
216
0
                break;
217
41
        }
218
41
        if (pparam->free_key) {
219
            /* We allocated this, so we must free it. */
220
41
            gs_free_const_string(mem, pparam->key.data, pparam->key.size,
221
41
                                 "gs_c_param_list_release key");
222
41
        }
223
41
        gs_free_object(mem, pparam->alternate_typed_data,
224
41
                       "gs_c_param_list_release alternate data");
225
41
        gs_free_object(mem, pparam,
226
41
                       "gs_c_param_list_release entry");
227
41
        plist->head = next;
228
41
        plist->count--;
229
41
    }
230
22.2k
}
231
232
/* Add an entry to a list.  Doesn't set: value, type, plist->head. */
233
static gs_c_param *
234
c_param_add(gs_c_param_list * plist, gs_param_name pkey)
235
41
{
236
41
    gs_c_param *pparam =
237
41
        gs_alloc_struct(plist->memory, gs_c_param, &st_c_param,
238
41
                        "c_param_add entry");
239
41
    uint len;
240
241
41
    if ((pparam == NULL) || (pkey == NULL))
242
0
        return NULL;
243
244
41
    len = strlen(pkey);
245
41
    pparam->next = plist->head;
246
41
    if (!plist->persistent_keys) {
247
        /* We must copy the key. */
248
41
        byte *str = gs_alloc_string(plist->memory, len, "c_param_add key");
249
250
41
        if (str == 0) {
251
0
            gs_free_object(plist->memory, pparam, "c_param_add entry");
252
0
            return 0;
253
0
        }
254
41
        memcpy(str, pkey, len);
255
41
        pparam->key.data = str;
256
41
        pparam->key.persistent = false; /* we will free it */
257
41
        pparam->free_key = true;
258
41
    } else {
259
0
        pparam->key.data = (const byte *)pkey;
260
0
        pparam->key.persistent = true;
261
0
        pparam->free_key = false;
262
0
    }
263
41
    pparam->key.size = len;
264
41
    pparam->alternate_typed_data = 0;
265
41
    pparam->error = 0;
266
41
    return pparam;
267
41
}
268
269
/*  Write a dynamically typed parameter to a list. */
270
static int
271
c_param_write(gs_c_param_list * plist, gs_param_name pkey, void *pvalue,
272
              gs_param_type type)
273
41
{
274
41
    unsigned top_level_sizeof = 0;
275
41
    unsigned second_level_sizeof = 0;
276
41
    gs_c_param *pparam = c_param_add(plist, pkey);
277
278
41
    if (pparam == 0)
279
0
        return_error(gs_error_VMerror);
280
41
    memcpy(&pparam->value, pvalue, gs_param_type_sizes[(int)type]);
281
41
    pparam->type = type;
282
283
    /* Need deeper copies of data if it's not persistent */
284
41
    switch (type) {
285
0
            gs_param_string const *curr_string;
286
0
            gs_param_string const *end_string;
287
288
0
        case gs_param_type_string_array:
289
0
        case gs_param_type_name_array:
290
            /* Determine how much mem needed to hold actual string data */
291
0
            curr_string = pparam->value.sa.data;
292
0
            end_string = curr_string + pparam->value.sa.size;
293
0
            for (; curr_string < end_string; ++curr_string)
294
0
                if (!curr_string->persistent)
295
0
                    second_level_sizeof += curr_string->size;
296
            /* fall thru */
297
298
41
        case gs_param_type_string:
299
41
        case gs_param_type_name:
300
41
        case gs_param_type_int_array:
301
41
        case gs_param_type_float_array:
302
41
            if (!pparam->value.s.persistent) { /* Allocate & copy object pointed to by array or string */
303
41
                byte *top_level_memory = NULL;
304
305
41
                top_level_sizeof =
306
41
                    pparam->value.s.size * gs_param_type_base_sizes[type];
307
41
                if (top_level_sizeof + second_level_sizeof > 0) {
308
41
                    top_level_memory =
309
41
                        gs_alloc_bytes_immovable(plist->memory,
310
41
                                     top_level_sizeof + second_level_sizeof,
311
41
                                             "c_param_write data");
312
41
                    if (top_level_memory == 0) {
313
0
                        if (pparam->key.persistent == false) {
314
0
                            gs_free_string(plist->memory, (byte *)(pparam->key.data),
315
0
                                strlen((const char *)(pparam->key.data)), "c_param_add key");
316
0
                        }
317
0
                        gs_free_object(plist->memory, pparam, "c_param_write entry");
318
0
                        return_error(gs_error_VMerror);
319
0
                    }
320
41
                    memcpy(top_level_memory, pparam->value.s.data, top_level_sizeof);
321
41
                }
322
41
                pparam->value.s.data = top_level_memory;
323
324
                /* String/name arrays need to copy actual str data */
325
326
41
                if (second_level_sizeof > 0) {
327
0
                    byte *second_level_memory =
328
0
                    top_level_memory + top_level_sizeof;
329
330
0
                    curr_string = pparam->value.sa.data;
331
0
                    end_string = curr_string + pparam->value.sa.size;
332
0
                    for (; curr_string < end_string; ++curr_string)
333
0
                        if (!curr_string->persistent) {
334
0
                            memcpy(second_level_memory,
335
0
                                   curr_string->data, curr_string->size);
336
0
                            ((gs_param_string *) curr_string)->data
337
0
                                = second_level_memory;
338
0
                            second_level_memory += curr_string->size;
339
0
                        }
340
0
                }
341
41
            }
342
41
            break;
343
41
        default:
344
0
            break;
345
41
    }
346
347
41
    plist->head = pparam;
348
41
    plist->count++;
349
41
    return 0;
350
41
}
351
352
/* Individual writing routines. */
353
static int
354
c_param_begin_write_collection(gs_param_list * plist, gs_param_name pkey,
355
               gs_param_dict * pvalue, gs_param_collection_type_t coll_type)
356
0
{
357
0
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
358
0
    gs_c_param_list *dlist =
359
0
        gs_c_param_list_alloc(cplist->memory,
360
0
                              "c_param_begin_write_collection");
361
362
0
    if (dlist == 0)
363
0
        return_error(gs_error_VMerror);
364
0
    gs_c_param_list_write(dlist, cplist->memory);
365
0
    dlist->coll_type = coll_type;
366
0
    pvalue->list = (gs_param_list *) dlist;
367
0
    return 0;
368
0
}
369
static int
370
c_param_end_write_collection(gs_param_list * plist, gs_param_name pkey,
371
                             gs_param_dict * pvalue)
372
0
{
373
0
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
374
0
    gs_c_param_list *dlist = (gs_c_param_list *) pvalue->list;
375
0
    int code;
376
377
0
    code = c_param_write(cplist, pkey, pvalue->list,
378
0
                    (dlist->coll_type == gs_param_collection_dict_int_keys ?
379
0
                     gs_param_type_dict_int_keys :
380
0
                     dlist->coll_type == gs_param_collection_array ?
381
0
                     gs_param_type_array : gs_param_type_dict));
382
383
0
    gs_free_object(plist->memory, pvalue->list, "c_param_end_write_collection");
384
0
    pvalue->list = 0;
385
0
    return code;
386
0
}
387
static int
388
c_param_write_typed(gs_param_list * plist, gs_param_name pkey,
389
                    gs_param_typed_value * pvalue)
390
41
{
391
41
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
392
41
    gs_param_collection_type_t coll_type;
393
394
41
    switch (pvalue->type) {
395
0
        case gs_param_type_dict:
396
0
            coll_type = gs_param_collection_dict_any;
397
0
            break;
398
0
        case gs_param_type_dict_int_keys:
399
0
            coll_type = gs_param_collection_dict_int_keys;
400
0
            break;
401
0
        case gs_param_type_array:
402
0
            coll_type = gs_param_collection_array;
403
0
            break;
404
41
        default:
405
41
            return c_param_write(cplist, pkey, &pvalue->value, pvalue->type);
406
41
    }
407
0
    return c_param_begin_write_collection
408
0
        (plist, pkey, &pvalue->value.d, coll_type);
409
41
}
410
411
/* Other procedures */
412
413
static int
414
c_param_request(gs_param_list * plist, gs_param_name pkey)
415
0
{
416
0
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
417
0
    gs_c_param *pparam;
418
419
0
    cplist->any_requested = true;
420
0
    if (c_param_find(cplist, pkey, true))
421
0
        return 0;
422
0
    pparam = c_param_add(cplist, pkey);
423
0
    if (pparam == 0)
424
0
        return_error(gs_error_VMerror);
425
0
    pparam->type = gs_param_type_any; /* mark as undefined */
426
0
    cplist->head = pparam;
427
0
    return 0;
428
0
}
429
430
static int
431
c_param_requested(const gs_param_list * plist, gs_param_name pkey)
432
0
{
433
0
    const gs_c_param_list *const cplist = (const gs_c_param_list *)plist;
434
0
    gs_param_list *target = cplist->target;
435
0
    int code;
436
437
0
    if (!cplist->any_requested)
438
0
        return (target ? param_requested(target, pkey) : -1);
439
0
    if (c_param_find(cplist, pkey, true) != 0)
440
0
        return 1;
441
0
    if (!target)
442
0
        return 0;
443
0
    code = param_requested(target, pkey);
444
0
    return (code < 0 ? 0 : 1);
445
0
}
446
447
/* ---------------- Reading from a list to parameters ---------------- */
448
449
static param_proc_begin_xmit_collection(c_param_begin_read_collection);
450
static param_proc_end_xmit_collection(c_param_end_read_collection);
451
static param_proc_xmit_typed(c_param_read_typed);
452
static param_proc_next_key(c_param_get_next_key);
453
static param_proc_get_policy(c_param_read_get_policy);
454
static param_proc_signal_error(c_param_read_signal_error);
455
static param_proc_read_signalled_error(c_param_read_signalled_error);
456
static param_proc_commit(c_param_read_commit);
457
static const gs_param_list_procs c_read_procs =
458
{
459
    c_param_read_typed,
460
    c_param_begin_read_collection,
461
    c_param_end_read_collection,
462
    c_param_get_next_key,
463
    NULL,     /* request, N/A */
464
    NULL,     /* requested, N/A */
465
    c_param_read_get_policy,
466
    c_param_read_signal_error,
467
    c_param_read_commit,
468
    c_param_read_signalled_error
469
};
470
471
/* Switch a list from writing to reading. */
472
void
473
gs_c_param_list_read(gs_c_param_list * plist)
474
41
{
475
41
    plist->procs = &c_read_procs;
476
41
}
477
478
/* Generic routine for reading a parameter from a list. */
479
480
static int
481
c_param_read_typed(gs_param_list * plist, gs_param_name pkey,
482
                   gs_param_typed_value * pvalue)
483
7.29k
{
484
7.29k
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
485
7.29k
    gs_param_type req_type = pvalue->type;
486
7.29k
    gs_c_param *pparam = c_param_find(cplist, pkey, false);
487
7.29k
    int code;
488
489
7.29k
    if (pparam == 0)
490
7.29k
        return (cplist->target ?
491
7.29k
                param_read_typed(cplist->target, pkey, pvalue) : 1);
492
0
    pvalue->type = pparam->type;
493
0
    switch (pvalue->type) {
494
0
        case gs_param_type_dict:
495
0
        case gs_param_type_dict_int_keys:
496
0
        case gs_param_type_array:
497
0
            gs_c_param_list_read(&pparam->value.d);
498
0
            pvalue->value.d.list = (gs_param_list *) & pparam->value.d;
499
0
            pvalue->value.d.size = pparam->value.d.count;
500
0
            return 0;
501
0
        default:
502
0
            break;
503
0
    }
504
0
    memcpy(&pvalue->value, &pparam->value,
505
0
           gs_param_type_sizes[(int)pparam->type]);
506
0
    code = param_coerce_typed(pvalue, req_type, NULL);
507
/****** SHOULD LET param_coerce_typed DO THIS ******/
508
0
    if (code == gs_error_typecheck &&
509
0
        req_type == gs_param_type_float_array &&
510
0
        pvalue->type == gs_param_type_int_array
511
0
        ) {
512
        /* Convert int array to float dest */
513
0
        gs_param_float_array fa;
514
0
        int element;
515
516
0
        fa.size = pparam->value.ia.size;
517
0
        fa.persistent = false;
518
519
0
        if (pparam->alternate_typed_data == 0) {
520
0
            if ((pparam->alternate_typed_data
521
0
                 = (void *)gs_alloc_bytes_immovable(cplist->memory,
522
0
                                                    fa.size * sizeof(float),
523
0
                             "gs_c_param_read alternate float array")) == 0)
524
0
                      return_error(gs_error_VMerror);
525
526
0
            for (element = 0; element < fa.size; ++element)
527
0
                ((float *)(pparam->alternate_typed_data))[element]
528
0
                    = (float)pparam->value.ia.data[element];
529
0
        }
530
0
        fa.data = (float *)pparam->alternate_typed_data;
531
532
0
        pvalue->value.fa = fa;
533
0
        pvalue->type = req_type;
534
0
        return 0;
535
0
    }
536
0
    return code;
537
0
}
538
539
/* Individual reading routines. */
540
static int
541
c_param_begin_read_collection(gs_param_list * plist, gs_param_name pkey,
542
               gs_param_dict * pvalue, gs_param_collection_type_t coll_type)
543
82
{
544
82
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
545
82
    gs_c_param *pparam = c_param_find(cplist, pkey, false);
546
547
82
    if (pparam == 0)
548
82
        return
549
82
            (cplist->target ?
550
0
             param_begin_read_collection(cplist->target,
551
82
                                         pkey, pvalue, coll_type) :
552
82
             1);
553
0
    switch (pparam->type) {
554
0
        case gs_param_type_dict:
555
0
            if (coll_type != gs_param_collection_dict_any)
556
0
                return_error(gs_error_typecheck);
557
0
            break;
558
0
        case gs_param_type_dict_int_keys:
559
0
            if (coll_type == gs_param_collection_array)
560
0
                return_error(gs_error_typecheck);
561
0
            break;
562
0
        case gs_param_type_array:
563
0
            break;
564
0
        default:
565
0
            return_error(gs_error_typecheck);
566
0
    }
567
0
    gs_c_param_list_read(&pparam->value.d);
568
0
    pvalue->list = (gs_param_list *) & pparam->value.d;
569
0
    pvalue->size = pparam->value.d.count;
570
0
    return 0;
571
0
}
572
static int
573
c_param_end_read_collection(gs_param_list * plist, gs_param_name pkey,
574
                            gs_param_dict * pvalue)
575
0
{
576
0
    return 0;
577
0
}
578
579
/* Other procedures */
580
static int      /* ret 0 ok, 1 if EOF, or -ve err */
581
c_param_get_next_key(gs_param_list * plist, gs_param_enumerator_t * penum,
582
                     gs_param_key_t * key)
583
0
{
584
0
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
585
0
    gs_c_param *pparam =
586
0
    (penum->pvoid ? ((gs_c_param *) (penum->pvoid))->next :
587
0
     cplist->head);
588
589
0
    if (pparam == 0)
590
0
        return 1;
591
0
    penum->pvoid = pparam;
592
0
    *key = pparam->key;
593
0
    return 0;
594
0
}
595
static int
596
c_param_read_get_policy(gs_param_list * plist, gs_param_name pkey)
597
0
{
598
0
    return gs_param_policy_ignore;
599
0
}
600
static int
601
c_param_read_signal_error(gs_param_list * plist, gs_param_name pkey, int code)
602
0
{
603
0
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
604
0
    gs_c_param *pparam = c_param_find(cplist, pkey, false);
605
606
0
    if (pparam)
607
0
        pparam->error = code;
608
609
0
    return 0;
610
0
}
611
static int
612
c_param_read_commit(gs_param_list * plist)
613
41
{
614
41
    return 0;
615
41
}
616
static int
617
c_param_read_signalled_error(gs_param_list * plist, gs_param_name pkey)
618
0
{
619
0
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
620
0
    gs_c_param *pparam = c_param_find(cplist, pkey, false);
621
622
0
    return (pparam ? pparam->error : 0);
623
0
}