Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pcl/pcjob.c
Line
Count
Source
1
/* Copyright (C) 2001-2024 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
/* pcjob.c -  PCL5 job control commands */
18
#include "std.h"
19
#include "gx.h"
20
#include "gsmemory.h"
21
#include "gspaint.h"
22
#include "gsmatrix.h"           /* for gsdevice.h */
23
#include "gsdevice.h"
24
#include "pcommand.h"
25
#include "pcursor.h"            /* for pcl_home_cursor() */
26
#include "pcstate.h"
27
#include "pcparam.h"
28
#include "pcdraw.h"
29
#include "pcpage.h"
30
#include "pjtop.h"
31
#include <stdlib.h>             /* for atof() */
32
#include "gzstate.h"
33
#include "plparams.h"
34
35
/* Commands */
36
37
int
38
pcl_do_printer_reset(pcl_state_t * pcs)
39
28.5k
{
40
28.5k
  int code = 0;
41
28.5k
    if (pcs->macro_level)
42
0
        return e_Range;         /* not allowed inside macro */
43
44
    /* reset the other parser in case we have gotten the
45
       pcl_printer_reset while in gl/2 mode. */
46
28.5k
    code = pcl_implicit_gl2_finish(pcs);
47
28.5k
    if (code < 0)
48
0
        return code;
49
    /* Print any partial page if not pclxl snippet mode. */
50
28.5k
    if (pcs->end_page == pcl_end_page_top) {
51
28.5k
        code = pcl_end_page_if_marked(pcs);
52
53
28.5k
        if (code < 0)
54
0
            return code;
55
        /* if duplex start on the front side of the paper */
56
28.5k
        if (pcs->duplex)
57
59
            code = put_param1_bool(pcs, "FirstSide", true);
58
28.5k
        if (code < 0)
59
0
            return code;
60
28.5k
    }
61
    /* unload fonts */
62
63
    /* Reset to user default state. */
64
28.5k
    return pcl_do_resets(pcs, pcl_reset_printer);
65
28.5k
}
66
67
static int                      /* ESC E */
68
pcl_printer_reset(pcl_args_t * pargs, pcl_state_t * pcs)
69
20.1k
{
70
20.1k
    return pcl_do_printer_reset(pcs);
71
20.1k
}
72
73
static int                      /* ESC % -12345 X */
74
pcl_exit_language(pcl_args_t * pargs, pcl_state_t * pcs)
75
10.7k
{
76
10.7k
    if (int_arg(pargs) != -12345)
77
3.33k
        return e_Range;
78
7.38k
    {
79
7.38k
        int code = pcl_printer_reset(pargs, pcs);
80
81
7.38k
        return (code < 0 ? code : e_ExitLanguage);
82
10.7k
    }
83
10.7k
}
84
85
static int                      /* ESC & l <num_copies> X */
86
pcl_number_of_copies(pcl_args_t * pargs, pcl_state_t * pcs)
87
2.41k
{
88
2.41k
    int i = int_arg(pargs);
89
90
2.41k
    if (i < 1)
91
27
        return 0;
92
2.39k
    pcs->num_copies = i;
93
2.39k
    return put_param1_int(pcs, "NumCopies", i);
94
2.41k
}
95
96
static int                      /* ESC & l <sd_enum> S */
97
pcl_simplex_duplex_print(pcl_args_t * pargs, pcl_state_t * pcs)
98
154
{
99
154
    int code;
100
154
    bool reopen = false;
101
102
    /* oddly the command goes to the next page irrespective of
103
       arguments */
104
154
    code = pcl_end_page_if_marked(pcs);
105
154
    if (code < 0)
106
0
        return code;
107
154
    code = pcl_home_cursor(pcs);
108
154
    if (code < 0)
109
0
        return code;
110
154
    switch (int_arg(pargs)) {
111
76
        case 0:
112
76
            pcs->duplex = false;
113
76
            pcs->back_side = false;
114
76
            break;
115
64
        case 1:
116
64
            pcs->duplex = true;
117
64
            pcs->back_side = false;
118
64
            pcs->bind_short_edge = false;
119
64
            break;
120
11
        case 2:
121
11
            pcs->duplex = true;
122
11
            pcs->back_side = false;
123
11
            pcs->bind_short_edge = true;
124
11
            break;
125
3
        default:
126
3
            return 0;
127
154
    }
128
151
    code = put_param1_bool(pcs, "Duplex", pcs->duplex);
129
151
    switch (code) {
130
0
        case 1:                /* reopen device */
131
0
            reopen = true;
132
151
        case 0:
133
151
            break;
134
0
        case gs_error_undefined:
135
0
            return 0;
136
0
        default:               /* error */
137
0
            if (code < 0)
138
0
                return code;
139
151
    }
140
151
    code = put_param1_bool(pcs, "FirstSide", !pcs->back_side);
141
151
    switch (code) {
142
0
        case 1:                /* reopen device */
143
0
            reopen = true;
144
151
        case 0:
145
151
            break;
146
0
        case gs_error_undefined:
147
0
            return 0;
148
0
        default:               /* error */
149
0
            if (code < 0)
150
0
                return code;
151
151
    }
152
151
    code = put_param1_bool(pcs, "BindShortEdge", pcs->bind_short_edge);
153
151
    switch (code) {
154
0
        case 1:                /* reopen device */
155
0
            reopen = true;
156
151
        case 0:
157
151
        case gs_error_undefined:
158
151
            break;
159
0
        default:               /* error */
160
0
            if (code < 0)
161
0
                return code;
162
151
    }
163
151
    return (reopen ? gs_setdevice_no_erase(pcs->pgs,
164
151
                                           gs_currentdevice(pcs->pgs)) : 0);
165
151
}
166
167
static int                      /* ESC & a <side_enum> G */
168
pcl_duplex_page_side_select(pcl_args_t * pargs, pcl_state_t * pcs)
169
46
{
170
46
    uint i = uint_arg(pargs);
171
46
    int code = 0;
172
173
    /* oddly the command goes to the next page irrespective of
174
       arguments */
175
46
    code = pcl_end_page_if_marked(pcs);
176
46
    if (i > 2)
177
40
        return 0;
178
179
    /* home the cursor even if the command has no effect */
180
6
    if (code >= 0) {
181
6
        int errcode = pcl_home_cursor(pcs);
182
6
        if (errcode < 0)
183
0
            return errcode;
184
6
    }
185
186
    /* if there is an error (code < 0) or the page is unmarked (code
187
       == 0) then nothing to update */
188
6
    if (code <= 0)
189
1
        return code;
190
191
192
5
    if (pcs->duplex) {
193
0
        switch (i) {
194
0
        case 0:
195
            /* do nothing, back_side was updated by
196
               pcl_end_page_if_marked() above */
197
0
            break;
198
0
        case 1:
199
0
            pcs->back_side = false;
200
0
            break;
201
0
        case 2:
202
0
            pcs->back_side = true;
203
0
            break;
204
0
        default:
205
            /* can't happen */
206
0
            break;
207
0
        }
208
0
        code = put_param1_bool(pcs, "FirstSide", !pcs->back_side);
209
0
    }
210
5
    return code;
211
5
}
212
213
static int                      /* ESC & l 1 T */
214
pcl_job_separation(pcl_args_t * pargs, pcl_state_t * pcs)
215
528
{
216
528
    int i = int_arg(pargs);
217
218
528
    if (i != 1)
219
229
        return 0;
220
        /**** NEED A DRIVER PROCEDURE FOR END-OF-JOB ****/
221
299
    return 0;
222
528
}
223
224
static int                      /* ESC & l <bin_enum> G */
225
pcl_output_bin_selection(pcl_args_t * pargs, pcl_state_t * pcs)
226
3
{
227
3
    uint i = uint_arg(pargs);
228
229
3
    if (i < 1 || i > 2)
230
2
        return e_Range;
231
1
    return put_param1_int(pcs, "OutputBin", i);
232
3
}
233
234
static int                      /* ESC & u <upi> B */
235
pcl_set_unit_of_measure(pcl_args_t * pargs, pcl_state_t * pcs)
236
61.4k
{
237
61.4k
    int num = int_arg(pargs);
238
239
61.4k
    if (num <= 96)
240
10
        num = 96;
241
61.4k
    else if (num >= 7200)
242
0
        num = 7200;
243
61.4k
    else if (7200 % num != 0) { /* Pick the exact divisor of 7200 with the smallest */
244
        /* relative error. */
245
41
        static const int values[] = {
246
41
            96, 100, 120, 144, 150, 160, 180, 200, 225, 240, 288,
247
41
            300, 360, 400, 450, 480, 600, 720, 800, 900,
248
41
            1200, 1440, 1800, 2400, 3600, 7200
249
41
        };
250
41
        const int *p = values;
251
252
658
        while (num > p[1])
253
617
            p++;
254
        /* Now *p < num < p[1]. */
255
41
        if ((p[1] - (float)num) / p[1] < ((float)num - *p) / *p)
256
39
            p++;
257
41
        num = *p;
258
41
    }
259
61.4k
    pcs->uom_cp = pcl_coord_scale / num;
260
61.4k
    return 0;
261
61.4k
}
262
263
/* Initialization */
264
static int
265
pcjob_do_registration(pcl_parser_state_t * pcl_parser_state,
266
                      gs_memory_t * mem)
267
16.0k
{                               /* Register commands */
268
16.0k
    DEFINE_ESCAPE_ARGS('E', "Printer Reset", pcl_printer_reset, pca_in_rtl)
269
16.0k
        DEFINE_CLASS('%') {
270
16.0k
        0, 'X', {
271
16.0k
    pcl_exit_language, pca_neg_ok | pca_big_error | pca_in_rtl}},
272
16.0k
        END_CLASS DEFINE_CLASS('&') {
273
16.0k
    'l', 'X',
274
16.0k
            PCL_COMMAND("Number of Copies", pcl_number_of_copies,
275
16.0k
                            pca_neg_ignore | pca_big_clamp)}, {
276
16.0k
    'l', 'S',
277
16.0k
            PCL_COMMAND("Simplex/Duplex Print", pcl_simplex_duplex_print,
278
16.0k
                            pca_neg_ignore | pca_big_ignore)}, {
279
16.0k
    'a', 'G',
280
16.0k
            PCL_COMMAND("Duplex Page Side Select",
281
16.0k
                            pcl_duplex_page_side_select,
282
16.0k
                            pca_neg_ignore | pca_big_ignore)}, {
283
16.0k
    'l', 'T',
284
16.0k
            PCL_COMMAND("Job Separation", pcl_job_separation,
285
16.0k
                            pca_neg_error | pca_big_error)}, {
286
16.0k
    'l', 'G',
287
16.0k
            PCL_COMMAND("Output Bin Selection", pcl_output_bin_selection,
288
16.0k
                            pca_neg_error | pca_big_error)}, {
289
16.0k
    'u', 'D',
290
16.0k
            PCL_COMMAND("Set Unit of Measure", pcl_set_unit_of_measure,
291
16.0k
                            pca_neg_error | pca_big_error | pca_in_rtl)},
292
16.0k
        END_CLASS return 0;
293
16.0k
}
294
295
static inline float
296
pcl_pjl_res(pcl_state_t * pcs)
297
16.0k
{
298
16.0k
    pjl_envvar_t *pres = pjl_proc_get_envvar(pcs->pjls, "resolution");
299
300
16.0k
    return atof(pres);
301
16.0k
}
302
303
static int
304
pcjob_do_copy(pcl_state_t *psaved, const pcl_state_t *pcs,
305
              pcl_copy_operation_t operation)
306
0
{
307
0
    if (operation & pcl_copy_after_overlay) {
308
0
        psaved->back_side = pcs->back_side;
309
0
    }
310
0
    return 0;
311
0
}
312
313
static int
314
pcjob_do_reset(pcl_state_t * pcs, pcl_reset_type_t type)
315
60.2k
{
316
60.2k
    int code;
317
318
60.2k
    if (type & (pcl_reset_initial | pcl_reset_printer)) {
319
        /* check for a resolution setting from PJL and set it right
320
           away, there is no pcl command to set the resolution so a
321
           state variable is not needed.  Don't override -r from the command line. */
322
60.2k
        if (!pcs->res_set_on_command_line) {
323
16.0k
            gx_device *pdev = gs_currentdevice(pcs->pgs);
324
16.0k
            float res[2];
325
16.0k
            gs_point device_res;
326
327
16.0k
            device_res.x = pdev->HWResolution[0];
328
16.0k
            device_res.y = pdev->HWResolution[1];
329
330
            /* resolution is always a single number in PJL */
331
16.0k
            res[0] = res[1] = pcl_pjl_res(pcs);
332
333
            /*
334
             * again we only have a single number from PJL so just
335
             *  check the width
336
             */
337
338
16.0k
            if (res[0] != 0 && res[0] != device_res.x) {
339
0
                code = put_param1_float_array(pcs, "HWResolution", res);
340
0
                if (code < 0)
341
0
                    return code;
342
0
                code = gs_erasepage(pcs->pgs);
343
0
                if (code < 0)
344
0
                    return code;
345
0
            }
346
16.0k
        }
347
348
60.2k
        pcs->num_copies = pjl_proc_vartoi(pcs->pjls,
349
60.2k
                                          pjl_proc_get_envvar(pcs->pjls,
350
60.2k
                                                              "copies"));
351
60.2k
        pcs->duplex =
352
60.2k
            !pjl_proc_compare(pcs->pjls,
353
60.2k
                              pjl_proc_get_envvar(pcs->pjls, "duplex"),
354
60.2k
                              "off") ? false : true;
355
60.2k
        pcs->bind_short_edge =
356
60.2k
            !pjl_proc_compare(pcs->pjls,
357
60.2k
                              pjl_proc_get_envvar(pcs->pjls, "binding"),
358
60.2k
                              "longedge") ? false : true;
359
60.2k
        pcs->back_side = false;
360
60.2k
        pcs->output_bin = 1;
361
60.2k
        code = put_param1_bool(pcs, "Duplex", pcs->duplex);
362
60.2k
        if (code < 0)
363
0
            return code;
364
60.2k
        code = put_param1_bool(pcs, "FirstSide", !pcs->back_side);
365
60.2k
        if (code < 0)
366
0
            return code;
367
60.2k
        code = put_param1_bool(pcs, "BindShortEdge", pcs->bind_short_edge);
368
60.2k
        if (code < 0)
369
0
            return code;
370
60.2k
        code = put_param1_int(pcs, "PageSpotColors", 0);
371
60.2k
        if (code < 0)
372
0
            return code;
373
60.2k
    }
374
375
60.2k
    if (type & (pcl_reset_initial ^ pcl_reset_cold ^ pcl_reset_printer))
376
60.2k
    {
377
60.2k
        pjl_envvar_t *pres;
378
379
60.2k
        pres = pjl_proc_get_envvar(pcs->pjls, "pdfmark");
380
60.2k
        if (strlen(pres) > 0) {
381
0
            code = pcl_pjl_pdfmark(pcs->memory, pcs->pgs->device, pres);
382
0
            if (code < 0)
383
0
                return code;
384
0
        }
385
386
60.2k
        pres = pjl_proc_get_envvar(pcs->pjls, "setdistillerparams");
387
60.2k
        if (strlen(pres) > 0) {
388
0
            code = pcl_pjl_setdistillerparams(pcs->memory, pcs->pgs->device, pres);
389
0
            if (code < 0)
390
0
                return code;
391
0
        }
392
60.2k
    }
393
394
60.2k
    if (type & (pcl_reset_initial | pcl_reset_printer | pcl_reset_overlay)) {
395
        /* rtl always uses native units for user units.  The hp
396
           documentation does not say what to do if the resolution is
397
           assymetric... */
398
60.2k
        pcl_args_t args;
399
400
60.2k
        if (pcs->personality == rtl) {
401
0
            float res[2];
402
403
            /* resolution is always a single number in PJL */
404
0
            res[0] = res[1] = pcl_pjl_res(pcs);
405
406
0
            if (res[0] != 0)
407
0
                arg_set_uint(&args, (uint)res[0]);
408
0
            else
409
0
                arg_set_uint(&args,
410
0
                             (uint) gs_currentdevice(pcs->pgs)->
411
0
                             HWResolution[0]);
412
0
        } else
413
60.2k
            arg_set_uint(&args, 300);
414
60.2k
        code = pcl_set_unit_of_measure(&args, pcs);
415
60.2k
        if (code < 0)
416
0
            return code;
417
60.2k
    }
418
60.2k
    return 0;
419
60.2k
}
420
const pcl_init_t pcjob_init = {
421
    pcjob_do_registration, pcjob_do_reset, pcjob_do_copy
422
};