Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/urf/urftop.c
Line
Count
Source
1
/* Copyright (C) 2019-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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
/* urftop.c */
17
/* Top-level API implementation of "URF" Language Interface */
18
19
#include "pltop.h"
20
#include "plmain.h"
21
#include "gserrors.h"
22
#include "gxdevice.h"
23
#include "gsstate.h"
24
#include "surfx.h"
25
#include "strimpl.h"
26
#include "stream.h"
27
#include "gscoord.h"
28
#include "gsicc_manage.h"
29
#include "gspaint.h"
30
31
/* Forward decls */
32
33
/************************************************************/
34
/******** Language wrapper implementation (see pltop.h) *****/
35
/************************************************************/
36
37
typedef enum
38
{
39
    ii_state_identifying = 0,
40
    ii_state_unirast,
41
    ii_state_unirast_header,
42
    ii_state_unirast_data,
43
    ii_state_flush
44
} ii_state;
45
46
/*
47
 * URF interpreter instance
48
 */
49
typedef struct urf_interp_instance_s {
50
    gs_memory_t       *memory;
51
    gx_device         *dev;
52
    gx_device         *nulldev;
53
54
    gs_color_space    *gray;
55
    gs_color_space    *rgb;
56
    gs_color_space    *cmyk;
57
58
    /* URF parser state machine */
59
    ii_state           state;
60
61
    int                pages;
62
63
    uint8_t            bpp;
64
    uint8_t            cs;
65
    uint8_t            duplexMode;
66
    uint8_t            printQuality;
67
    uint8_t            mediaType;
68
    uint8_t            inputSlot;
69
    uint8_t            outputBin;
70
    uint8_t            copies;
71
    uint32_t           finishings;
72
    uint32_t           width;
73
    uint32_t           height;
74
    uint32_t           resolution;
75
76
    uint32_t           num_comps;
77
    uint32_t           byte_width;
78
    uint32_t           x;
79
    uint32_t           y;
80
81
    gs_image_t         image;
82
    gs_image_enum     *penum;
83
    gs_gstate         *pgs;
84
85
    stream_URFD_state  urfd_state;
86
    byte               stream_buffer[2048];
87
88
} urf_interp_instance_t;
89
90
static int
91
urf_detect_language(const char *s, int len)
92
17.7k
{
93
    /* For postscript, we look for %! */
94
17.7k
    if (len >= 8) {
95
17.3k
        if (strncmp(s, "UNIRAST", len) == 0)
96
0
            return 100;
97
17.3k
    }
98
    /* FIXME: Other formats go here */
99
100
17.7k
    return 0;
101
17.7k
}
102
103
static const pl_interp_characteristics_t urf_characteristics = {
104
    "URF",
105
    urf_detect_language
106
};
107
108
/* Get implementation's characteristics */
109
static const pl_interp_characteristics_t * /* always returns a descriptor */
110
urf_impl_characteristics(const pl_interp_implementation_t *impl)     /* implementation of interpreter to alloc */
111
37.5k
{
112
37.5k
  return &urf_characteristics;
113
37.5k
}
114
115
static void
116
urf_deallocate(urf_interp_instance_t *urf)
117
8.09k
{
118
8.09k
    if (urf == NULL)
119
0
        return;
120
121
8.09k
    rc_decrement_cs(urf->gray, "urf_deallocate");
122
8.09k
    rc_decrement_cs(urf->rgb, "urf_deallocate");
123
8.09k
    rc_decrement_cs(urf->cmyk, "urf_deallocate");
124
125
8.09k
    if (urf->pgs != NULL)
126
8.09k
        gs_gstate_free_chain(urf->pgs);
127
8.09k
    gs_free_object(urf->memory, urf, "urf_impl_allocate_interp_instance");
128
8.09k
}
129
130
/* Deallocate a interpreter instance */
131
static int
132
urf_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
133
8.09k
{
134
8.09k
    urf_interp_instance_t *urf = (urf_interp_instance_t *)impl->interp_client_data;
135
136
8.09k
    urf_deallocate(urf);
137
8.09k
    impl->interp_client_data = NULL;
138
139
8.09k
    return 0;
140
8.09k
}
141
142
/* Do per-instance interpreter allocation/init. */
143
static int
144
urf_impl_allocate_interp_instance(pl_interp_implementation_t *impl, gs_memory_t *mem)
145
8.09k
{
146
8.09k
    int code;
147
8.09k
    urf_interp_instance_t *urf
148
8.09k
        = (urf_interp_instance_t *)gs_alloc_bytes(mem,
149
8.09k
                                                  sizeof(urf_interp_instance_t),
150
8.09k
                                                  "urf_impl_allocate_interp_instance");
151
8.09k
    if (!urf)
152
0
        return_error(gs_error_VMerror);
153
8.09k
    memset(urf, 0, sizeof(*urf));
154
155
8.09k
    urf->memory = mem;
156
8.09k
    urf->pgs = gs_gstate_alloc(mem);
157
8.09k
    if (urf->pgs == NULL)
158
0
        goto failVM;
159
160
    /* Push one save level onto the stack to assuage the memory handling */
161
8.09k
    code = gs_gsave(urf->pgs);
162
8.09k
    if (code < 0)
163
0
        goto fail;
164
165
8.09k
    code = gsicc_init_iccmanager(urf->pgs);
166
8.09k
    if (code < 0)
167
0
        goto fail;
168
169
8.09k
    urf->gray = gs_cspace_new_ICC(mem, urf->pgs, 1);
170
8.09k
    urf->rgb  = gs_cspace_new_ICC(mem, urf->pgs, 3);
171
8.09k
    urf->cmyk = gs_cspace_new_ICC(mem, urf->pgs, 4);
172
173
8.09k
    impl->interp_client_data = urf;
174
175
8.09k
    return 0;
176
177
0
failVM:
178
0
    code = gs_note_error(gs_error_VMerror);
179
0
fail:
180
0
    (void)urf_deallocate(urf);
181
0
    return code;
182
0
}
183
184
/*
185
 * Get the allocator with which to allocate a device
186
 */
187
static gs_memory_t *
188
urf_impl_get_device_memory(pl_interp_implementation_t *impl)
189
0
{
190
0
    urf_interp_instance_t *urf = (urf_interp_instance_t *)impl->interp_client_data;
191
192
0
    return urf->dev ? urf->dev->memory : NULL;
193
0
}
194
195
#if 0 /* UNUSED */
196
static int
197
urf_impl_set_param(pl_interp_implementation_t *impl,
198
                   pl_set_param_type           type,
199
                   const char                 *param,
200
                   const void                 *val)
201
{
202
    urf_interp_instance_t *urf = (urf_interp_instance_t *)impl->interp_client_data;
203
204
    /* No params set here */
205
    return 0;
206
}
207
208
static int
209
urf_impl_add_path(pl_interp_implementation_t *impl,
210
                  const char                 *path)
211
{
212
    urf_interp_instance_t *urf = (urf_interp_instance_t *)impl->interp_client_data;
213
214
    /* No paths to add */
215
    return 0;
216
}
217
218
static int
219
urf_impl_post_args_init(pl_interp_implementation_t *impl)
220
{
221
    urf_interp_instance_t *urf = (urf_interp_instance_t *)impl->interp_client_data;
222
223
    /* No post args processing */
224
    return 0;
225
}
226
#endif
227
228
/* Prepare interp instance for the next "job" */
229
static int
230
urf_impl_init_job(pl_interp_implementation_t *impl,
231
                  gx_device                  *device)
232
0
{
233
0
    urf_interp_instance_t *urf = (urf_interp_instance_t *)impl->interp_client_data;
234
235
0
    urf->dev = device;
236
0
    urf->state = ii_state_identifying;
237
238
0
    return 0;
239
0
}
240
241
#if 0 /* UNUSED */
242
static int
243
urf_impl_run_prefix_commands(pl_interp_implementation_t *impl,
244
                             const char                 *prefix)
245
{
246
    urf_interp_instance_t *urf = (urf_interp_instance_t *)impl->interp_client_data;
247
248
    return 0;
249
}
250
251
static int
252
urf_impl_process_file(pl_interp_implementation_t *impl, const char *filename)
253
{
254
    urf_interp_instance_t *urf = (urf_interp_instance_t *)impl->interp_client_data;
255
256
    return 0;
257
}
258
#endif
259
260
/* Do any setup for parser per-cursor */
261
static int                      /* ret 0 or +ve if ok, else -ve error code */
262
urf_impl_process_begin(pl_interp_implementation_t * impl)
263
0
{
264
0
    return 0;
265
0
}
266
267
/* Ensure we have 'required' bytes to read, and further ensure
268
 * that we have no UEL's within those bytes. */
269
static int
270
ensure_bytes(urf_interp_instance_t *urf, stream_cursor_read *pr, int required)
271
0
{
272
0
    int n;
273
0
    const uint8_t *p = pr->ptr+1;
274
0
    const uint8_t *q;
275
0
    int avail;
276
277
    /* Find out how many bytes we need to check */
278
0
    n = pr->limit - pr->ptr;
279
0
    if (n > required)
280
0
        n = required;
281
282
    /* Make sure there are no UELs in that block */
283
0
    q = p + n;
284
0
    while (p != q) {
285
0
        while (p != q && *p != '\033')
286
0
            p++;
287
0
        if (p == q)
288
0
            break;
289
0
        avail = pr->limit - pr->ptr;
290
0
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
291
            /* At least a partial match to a UEL */
292
0
            return avail < 9 ? gs_error_NeedInput : gs_error_InterpreterExit;
293
0
        }
294
0
        p++;
295
0
    }
296
297
    /* If we have enough bytes, great, if not, get some more */
298
0
    return (n < required) ? gs_error_NeedInput : 0;
299
0
}
300
301
static int
302
flush_to_uel(stream_cursor_read *pr)
303
0
{
304
0
    const uint8_t *p = pr->ptr+1;
305
0
    const uint8_t *q = pr->limit+1;
306
0
    int avail;
307
308
0
    while (p != q) {
309
0
        while (p != q && *p != '\033')
310
0
            p++;
311
0
        if (p == q)
312
0
            break;
313
0
        avail = pr->limit - pr->ptr;
314
0
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
315
            /* At least a partial match to a UEL. Bin everything to
316
             * the start of the match. */
317
0
            pr->ptr = p-1;
318
0
            if (avail == 9) /* Complete match. Exit! */
319
0
                return gs_error_InterpreterExit;
320
            /* Partial match. Get more data. */
321
0
            return gs_error_NeedInput;
322
0
        }
323
0
        p++;
324
0
    }
325
326
0
    pr->ptr = pr->limit;
327
328
0
    return 0;
329
0
}
330
331
static int
332
bytes_until_uel(const stream_cursor_read *pr)
333
0
{
334
0
    const uint8_t *p = pr->ptr+1;
335
0
    const uint8_t *q = pr->limit+1;
336
0
    int avail;
337
338
0
    while (p != q) {
339
0
        while (p != q && *p != '\033')
340
0
            p++;
341
0
        if (p == q)
342
0
            break;
343
0
        avail = pr->limit - pr->ptr;
344
0
        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
345
            /* At least a partial match to a UEL. Everything up to
346
             * the start of the match is up for grabs. */
347
0
            return p - (pr->ptr+1);
348
0
        }
349
0
        p++;
350
0
    }
351
352
0
    return pr->limit - pr->ptr;
353
0
}
354
355
static int
356
get32be(stream_cursor_read *pr)
357
0
{
358
0
    int v = pr->ptr[1] << 24;
359
0
    v |= pr->ptr[2] << 16;
360
0
    v |= pr->ptr[3] << 8;
361
0
    v |= pr->ptr[4];
362
0
    pr->ptr += 4;
363
364
0
    return v;
365
0
}
366
367
static int
368
get8(stream_cursor_read *pr)
369
0
{
370
0
    return *++(pr->ptr);
371
0
}
372
373
static int
374
urf_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr)
375
0
{
376
0
    urf_interp_instance_t *urf = (urf_interp_instance_t *)impl->interp_client_data;
377
0
    int code = 0;
378
0
    gs_color_space *cs;
379
380
    /* Loop while we have bytes to read */
381
0
    while (pr->limit > pr->ptr)
382
0
    {
383
0
        switch(urf->state)
384
0
        {
385
0
        case ii_state_identifying:
386
            /* Try and get us 8 bytes for "UNIRAST\0" */
387
0
            code = ensure_bytes(urf, pr, 8);
388
0
            if (code < 0)
389
0
                return code;
390
0
            if (strncmp("UNIRAST", (const char *)pr->ptr+1, 8) == 0)
391
0
            {
392
0
                pr->ptr += 8;
393
0
                urf->state = ii_state_unirast;
394
0
                break;
395
0
            }
396
0
            urf->state = ii_state_flush;
397
0
            break;
398
0
        case ii_state_unirast:
399
            /* Try and get us 4 bytes for the page count */
400
0
            code = ensure_bytes(urf, pr, 4);
401
0
            if (code < 0)
402
0
                return code;
403
0
            urf->pages = get32be(pr);
404
0
            if (urf->pages == 0)
405
0
                urf->pages = -1;
406
0
            urf->state = ii_state_unirast_header;
407
0
            break;
408
0
        case ii_state_unirast_header:
409
0
            code = ensure_bytes(urf, pr, 32);
410
0
            if (code < 0)
411
0
                return code;
412
0
            urf->bpp          = get8(pr);
413
0
            urf->cs           = get8(pr);
414
0
            urf->duplexMode   = get8(pr);
415
0
            urf->printQuality = get8(pr);
416
0
            urf->mediaType    = get8(pr);
417
0
            urf->inputSlot    = get8(pr);
418
0
            urf->outputBin    = get8(pr);
419
0
            urf->copies       = get8(pr);
420
0
            if (urf->copies == 0)
421
0
                urf->copies = 1;
422
0
            urf->finishings   = get32be(pr);
423
0
            urf->width        = get32be(pr);
424
0
            urf->height       = get32be(pr);
425
0
            urf->resolution   = get32be(pr);
426
0
            (void)get32be(pr);
427
0
            (void)get32be(pr);
428
429
            /* Decode the header */
430
0
            switch(urf->cs) {
431
0
            case 0: /* W */
432
0
            case 4: /* DeviceW */
433
0
                urf->num_comps = 1;
434
0
                cs = urf->gray;
435
0
                break;
436
0
            case 1: /* sRGB */
437
0
            case 5: /* DeviceRGB */
438
0
                urf->num_comps = 3;
439
0
                cs = urf->rgb;
440
0
                break;
441
0
            case 6: /* CMYK */
442
0
                urf->num_comps = 4;
443
0
                cs = urf->cmyk;
444
0
                break;
445
0
            default:
446
0
                goto bad_header;
447
0
            }
448
0
            if (urf->bpp != 8*urf->num_comps && urf->bpp != 16*urf->num_comps) {
449
0
bad_header:
450
0
                urf->state = ii_state_flush;
451
0
                break;
452
0
            }
453
0
            urf->byte_width = (urf->bpp>>3)*urf->width;
454
455
0
            if (urf->nulldev == NULL)
456
0
            {
457
0
                urf->nulldev = gs_currentdevice(urf->pgs);
458
0
                rc_increment(urf->nulldev);
459
0
                code = gs_setdevice_no_erase(urf->pgs, urf->dev);
460
0
                if (code < 0)
461
0
                    goto early_flush;
462
0
            }
463
0
            gs_initmatrix(urf->pgs);
464
465
            /* By default the ctm is set to:
466
             *   xres/72   0
467
             *   0         -yres/72
468
             *   0         dev->height * yres/72
469
             * i.e. it moves the origin from being top right to being bottom left.
470
             * We want to move it back, as without this, the image will be displayed
471
             * upside down.
472
             */
473
0
            code = gs_translate(urf->pgs, 0.0, urf->dev->height * 72 / urf->dev->HWResolution[1]);
474
0
            if (code >= 0)
475
0
                code = gs_scale(urf->pgs, 1, -1);
476
            /* At this point, the ctm is set to:
477
             *   xres/72  0
478
             *   0        yres/72
479
             *   0        0
480
             */
481
0
            if (code >= 0)
482
0
                code = gs_erasepage(urf->pgs);
483
0
            if (code < 0)
484
0
                goto early_flush;
485
486
0
            memset(&urf->image, 0, sizeof(urf->image));
487
0
            gs_image_t_init(&urf->image, cs);
488
0
            urf->image.BitsPerComponent = urf->bpp/urf->num_comps;
489
0
            urf->image.Width = urf->width;
490
0
            urf->image.Height = urf->height;
491
492
0
            urf->image.ImageMatrix.xx = urf->resolution / 72.0f;
493
0
            urf->image.ImageMatrix.yy = urf->resolution / 72.0f;
494
495
0
            urf->penum = gs_image_enum_alloc(urf->memory, "urf_impl_process(penum)");
496
0
            if (urf->penum == NULL) {
497
0
                code = gs_note_error(gs_error_VMerror);
498
0
                goto early_flush;
499
0
            }
500
501
0
            code = gs_image_init(urf->penum,
502
0
                                 &urf->image,
503
0
                                 false,
504
0
                                 false,
505
0
                                 urf->pgs);
506
0
            if (code < 0)
507
0
                goto early_flush;
508
509
0
            s_init_state((stream_state *)&urf->urfd_state, &s_URFD_template, urf->memory);
510
0
            if (s_URFD_template.set_defaults)
511
0
                s_URFD_template.set_defaults((stream_state *)&urf->urfd_state);
512
513
0
            urf->urfd_state.width = urf->width;
514
0
            urf->urfd_state.bpp = urf->bpp;
515
0
            urf->urfd_state.white = urf->num_comps == 4 ? 0xff : 0;
516
517
0
            code = (s_URFD_template.init)((stream_state *)&urf->urfd_state);
518
0
            if (code < 0)
519
0
                goto early_flush;
520
0
            urf->x = urf->y = 0;
521
0
            urf->state = ii_state_unirast_data;
522
0
            break;
523
0
        case ii_state_unirast_data:
524
0
        {
525
0
            int n = bytes_until_uel(pr);
526
0
            stream_cursor_read local_r;
527
0
            stream_cursor_write local_w;
528
0
            int status;
529
0
            unsigned int used;
530
0
            int decoded_any = 0;
531
532
0
            local_r.ptr = pr->ptr;
533
0
            local_r.limit = local_r.ptr + n;
534
535
0
            do {
536
0
                local_w.ptr = urf->stream_buffer-1;
537
0
                local_w.limit = local_w.ptr + sizeof(urf->stream_buffer);
538
539
0
                status = (s_URFD_template.process)((stream_state *)&urf->urfd_state,
540
0
                                                                   &local_r, &local_w,
541
0
                                                                   true);
542
0
                (void)status;
543
544
                /* status = 0 => need data
545
                 *          1 => need output space */
546
                /* Copy the updated pointer back */
547
0
                if (pr->ptr != local_r.ptr)
548
0
                {
549
                    /* We may not have actually decoded anything, but we consumed some, so
550
                     * progress was made! */
551
0
                    decoded_any = 1;
552
0
                    pr->ptr = local_r.ptr;
553
0
                }
554
0
                if (local_w.ptr + 1 == urf->stream_buffer)
555
0
                    break; /* Failed to decode any data */
556
0
                decoded_any = 1;
557
558
                /* FIXME: Do we need to byte swap 16bit data? */
559
0
                code = gs_image_next(urf->penum, urf->stream_buffer, local_w.ptr + 1 - urf->stream_buffer, &used);
560
0
                if (code < 0)
561
0
                    goto flush;
562
563
0
                urf->x += used;
564
0
                while (urf->x >= urf->byte_width) {
565
0
                    urf->x -= urf->byte_width;
566
0
                    urf->y++;
567
0
                }
568
                /* Loop while we haven't had all the lines, the decompression
569
                 * didn't ask for more data, and the decompression didn't give
570
                 * us more data. */
571
0
            } while (urf->y < urf->height);
572
573
0
            if (urf->y == urf->height) {
574
0
                code = gs_image_cleanup_and_free_enum(urf->penum, urf->pgs);
575
0
                urf->penum = NULL;
576
0
                if (code < 0)
577
0
                    goto flush;
578
0
                code = pl_finish_page(urf->memory->gs_lib_ctx->top_of_system,
579
0
                                      urf->pgs, urf->copies, true);
580
0
                if (code < 0)
581
0
                    goto flush;
582
0
                if (urf->pages > 0) {
583
0
                    urf->pages--;
584
                    /* If we've reached the expected end, we should probably flush to UEL */
585
0
                    if (urf->pages == 0)
586
0
                        urf->state = ii_state_flush;
587
0
                }
588
0
                urf->urfd_state.templat->release((stream_state *)&urf->urfd_state);
589
0
                urf->state = ii_state_unirast_header;
590
0
            } else if (decoded_any == 0) {
591
                /* Failed to make progress. Just give up to avoid livelocking. */
592
0
                goto flush;
593
0
            }
594
0
            break;
595
0
        }
596
0
        default:
597
0
        case ii_state_flush:
598
0
            if (0) {
599
0
flush:
600
0
                urf->urfd_state.templat->release((stream_state *)&urf->urfd_state);
601
0
early_flush:
602
0
                urf->state = ii_state_flush;
603
0
            }
604
            /* We want to bin any data we get up to, but not including
605
             * a UEL. */
606
0
            return flush_to_uel(pr);
607
0
        }
608
0
    }
609
610
0
    return code;
611
0
}
612
613
static int
614
urf_impl_process_end(pl_interp_implementation_t * impl)
615
0
{
616
0
    return 0;
617
0
}
618
619
/* Not implemented */
620
static int
621
urf_impl_flush_to_eoj(pl_interp_implementation_t *impl, stream_cursor_read *cursor)
622
0
{
623
0
    const byte *p = cursor->ptr;
624
0
    const byte *rlimit = cursor->limit;
625
626
    /* Skip to, but leave UEL in buffer for PJL to find later */
627
0
    for (; p < rlimit; ++p)
628
0
        if (p[1] == '\033') {
629
0
            uint avail = rlimit - p;
630
631
0
            if (memcmp(p + 1, "\033%-12345X", min(avail, 9)))
632
0
                continue;
633
0
            if (avail < 9)
634
0
                break;
635
0
            cursor->ptr = p;
636
0
            return 1;           /* found eoj */
637
0
        }
638
0
    cursor->ptr = p;
639
0
    return 0;                   /* need more */
640
0
}
641
642
/* Parser action for end-of-file */
643
static int
644
urf_impl_process_eof(pl_interp_implementation_t *impl)
645
0
{
646
0
    return 0;
647
0
}
648
649
/* Report any errors after running a job */
650
static int
651
urf_impl_report_errors(pl_interp_implementation_t *impl,          /* interp instance to wrap up job in */
652
                       int                         code,          /* prev termination status */
653
                       long                        file_position, /* file position of error, -1 if unknown */
654
                       bool                        force_to_cout  /* force errors to cout */
655
)
656
0
{
657
0
    return 0;
658
0
}
659
660
/* Wrap up interp instance after a "job" */
661
static int
662
urf_impl_dnit_job(pl_interp_implementation_t *impl)
663
0
{
664
0
    urf_interp_instance_t *urf = (urf_interp_instance_t *)impl->interp_client_data;
665
666
0
    if (urf->nulldev) {
667
0
        int code = gs_setdevice(urf->pgs, urf->nulldev);
668
0
        urf->dev = NULL;
669
0
        rc_decrement(urf->nulldev, "urf_impl_dnit_job(nulldevice)");
670
0
        urf->nulldev = NULL;
671
0
        return code;
672
0
    }
673
0
    return 0;
674
0
}
675
676
/* Parser implementation descriptor */
677
const pl_interp_implementation_t urf_implementation = {
678
  urf_impl_characteristics,
679
  urf_impl_allocate_interp_instance,
680
  urf_impl_get_device_memory,
681
  NULL, /* urf_impl_set_param */
682
  NULL, /* urf_impl_add_path */
683
  NULL, /* urf_impl_post_args_init */
684
  urf_impl_init_job,
685
  NULL, /* urf_impl_run_prefix_commands */
686
  NULL, /* urf_impl_process_file */
687
  urf_impl_process_begin,
688
  urf_impl_process,
689
  urf_impl_process_end,
690
  urf_impl_flush_to_eoj,
691
  urf_impl_process_eof,
692
  urf_impl_report_errors,
693
  urf_impl_dnit_job,
694
  urf_impl_deallocate_interp_instance,
695
  NULL
696
};