1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
|
/* Portions Copyright (C) 2001 artofcode LLC.
Portions Copyright (C) 1996, 2001 Artifex Software Inc.
Portions Copyright (C) 1988, 2000 Aladdin Enterprises.
This software is based in part on the work of the Independent JPEG Group.
All Rights Reserved.
This software is distributed under license and may not be copied, modified
or distributed except as expressly authorized under the terms of that
license. Refer to licensing information at http://www.artifex.com/ or
contact Artifex Software, Inc., 101 Lucas Valley Road #110,
San Rafael, CA 94903, (415)492-9861, for further information. */
/*$Id$ */
/* pcursor.c - PCL5 cursor positioning commands */
#include "std.h"
#include "math_.h"
#include "pcommand.h"
#include "pcstate.h"
#include "pcdraw.h"
#include "pcpatxfm.h"
#include "pcfont.h"
#include "pcursor.h"
#include "pcpage.h"
#include "gscoord.h"
#include "pjtop.h"
/*
* Hoizontal and vertical movement.
*
* This is one of the most confusing areas of PCL because the individual
* movement commands and margins evolved at different times in the history
* of PCL, and thus have different behavior. In the dicussion below, we
* divide the various horizontal and vertical motion commands into groups,
* and identify the interaction of each group with the corresponding horizontal
* or vertical boundaries. (Note that, if the current print direciton is not
* zero, what is called the "left" logical page boundary would, from the
* point of view of the logical page, be given a different label.)
*
* Horizontal motion commmands (note: a movement "transitions" a boundary if
* the current point before and after the movement is on opposite sides of
* the boundary):
*
* a. Horizontal position by column, decipoint, or PCL unit, in absolute
* or relative mode, and horizontal motion due to rasters:
*
* "left" logical page boundary is used as origin for absolute positions
* movement to the left of the left logical page boundary is clamped
* to that boundary
* left text boundary is ignored
* right text boundary is ignored
* movement beyond the "right" logical page boundary is clamped to
* that boundary
*
* b. Tab (always relative)
*
* "left" logical boundary is irrelevant
* left text boundary is used as the origin for tab stops
* movement that transitions the right text boundary is clamped to
* that boundary
* movement beyond the "right" logical page boundary is clamped
* to that boundary
*
* c. Character or space (code legal in symbol set up not occupied by a
* printable character; motion always relative)
*
* "left" logical page boundary is irrelevant
* left text boundary is ignored
* if the character WOULD transition the right text boundary, ignore
* the character or issue a CR/LF sequence BEFORE printing the
* character, base on whether or not end-of-line wrapping is
* enabled (with one exception; see below)
* if the character WOULD transition the "right" logical page boundary,
* ignore the character or issue a CR/LF sequence BEFORE printing
* the character, base on whether or not end-of-line wrapping is
* enabled
*
* Note that only one of the latter two operations will be preformed if
* the logical and text margins are the same.
*
* An exception is made in third case above in the event that a back-
* space was received immediately before the character to be rendered.
* In that case, the character is rendered regardless of the transition
* of the right text boundary.
*
* d. Carriage return (always absolute)
*
* "left" logical page boundary is irrelevant
* left text boundary is used as the new horizontal location
* right text boundary is irrelevant
* "right" logical page boundary is irrelevant
*
* e. Back space
*
* movement beyond the "left" logical page boundary is clamped to
* that boundary
* movement that would transition the left text boundary is clamped
* to that boundary
* right text boundary is ignored (this is contrary to HP's
* documentation, but empirically verified on several machines)
* "right" logical page boundary is irrelevant
*
* In addtion, any horizontal movement to the left will "break" the current
* underline (this is significant for floating underlines).
*
* Vertical motion commands:
*
* f. Vertical cursor position by decipoints or PCL units (but NOT by
* rows), both absolute and relative
*
* movement beyond the "top" logical page boundary is clamped to
* that boundary
* top text boundary is used as the origin for absolute moves
* bottom text margin is ignored
* movement beyond the "bottom" logical page boundary is clamped to
* that boundary
*
* g. Absolute (NOT relative) vertical cursor position by rows
*
* "top" logical page boundary is irrelevant (can only be reached by
* relative moves)
* top text boundary, offset by 75% of the VMI distance, is used as
* the origin
* bottom text margin is ignored
* movement beyond the "bottom" logical page boundary is clamped to
* that boundary
*
* h. Relative (NOT absolute) vertical cursor position by rows, and both
* line-feed and half line-feed when perforation skip is disabled
*
* movement beyond the "top" logical page boundary is clamped to
* that boundary
* if and advance of n rows (n == 1 for LF) is requested, and only
* m additional rows can be accommodated on the current page,
* an implicit page ejection occurs and the cursor is positioned
* n - m rows below the "top" logical page boundary on the
* subsequent page; if the subsequent page will not accommodate
* n - m rows, the process is repeated
* after an implicit page eject (see below), the cursor is positioned
* 75% of the VMI distance below the "top" logical page boundary plus
*
* top text boundary is ignored
* bottom text boundary is ignored
* movement beyond the "bottom" page boundary causes an implicit
* page eject
*
* i. Line-feed and halft line feed, when perforation skip is enabled
*
* "top" logical page boundary is irrelevant
* after an implicit page eject (see below), the cursor is set 75% of
* the VMI distance below the top text boundary
* any movement that ends below the bottom text boundary causes a
* page eject (NB: this does not require a transition of the
* boundary, as is the case for the right text boundary)
* the "bottom" logical page boundary is irrelevant
*
* j. Form feed
*
* "top" logical page boundary is irrelevant
* the cursor is positioned 75% of the VMI distance below the top
* text boundary
* bottom text boundary is irrelevant
* "bottom" logical page boundary is irrelevant
*
*
* k. for a relative vertical motion command relative movement can extend
* to the next logical page's lower boundary, where it is clamped.
* This should could be grouped with item h.
*
* Wow - 11 different forms to accommodate.
*
* The special handling required by character and space induced horizontal
* movement is handled in pctext.c (pcl_show_chars); all other movement is
* handled in this file.
*/
#define HOME_X(pcs) (pcs->margins.left)
#define DEFAULT_Y_START(pcs) ((3L * pcs->vmi_cp) / 4L)
#define HOME_Y(pcs) (pcs->margins.top + DEFAULT_Y_START(pcs))
void
pcl_set_cap_x(
pcl_state_t * pcs,
coord x,
bool relative,
bool use_margins
)
{
coord old_x = pcs->cap.x;
if (relative)
x += pcs->cap.x;
/* the horizontal text margins are only interesting in transition */
if (use_margins) {
coord min_x = pcs->margins.left;
coord max_x = pcs->margins.right;
if ((old_x >= min_x) && (x < min_x))
x = min_x;
else if ((old_x <= max_x) && (x > max_x))
x = max_x;
}
/* the logical page bounds always apply */
x = ( x > pcs->xfm_state.pd_size.x ? pcs->xfm_state.pd_size.x
: (x < 0L ? 0L : x) );
/* leftward motion "breaks" an underline */
if (x < old_x) {
pcl_break_underline(pcs);
pcs->cap.x = x;
pcl_continue_underline(pcs);
} else
pcs->cap.x = x;
}
int
pcl_set_cap_y(
pcl_state_t * pcs,
coord y,
bool relative,
bool use_margins,
bool by_row,
bool by_row_command
)
{
coord lim_y = pcs->xfm_state.pd_size.y;
coord max_y = pcs->margins.top + pcs->margins.length;
bool page_eject = by_row && relative;
/* this corresponds to rule 'k' above. */
if (relative && by_row_command) {
/* calculate the advance to the next logical page bound. Note
margins are false if by_row_command is true. */
coord advance_max = 2 * lim_y - pcs->cap.y;
/* clamp */
y = (y < advance_max ? y : advance_max + HOME_Y(pcs));
}
/* adjust the vertical position provided */
if (relative)
y += pcs->cap.y;
else
y += (by_row ? HOME_Y(pcs) : pcs->margins.top);
/* vertical moves always "break" underlines */
pcl_break_underline(pcs);
max_y = (use_margins ? max_y : lim_y);
if (y < 0L)
pcs->cap.y = 0L;
else if (y <= max_y)
pcs->cap.y = y;
else if (!page_eject)
pcs->cap.y = (y <= lim_y ? y : lim_y);
else {
coord vmi_cp = pcs->vmi_cp;
coord y0 = pcs->cap.y;
while (y > max_y) {
int code = pcl_end_page_always(pcs);
if (code < 0)
return code;
y -= (y0 <= max_y ? max_y : y0);
y0 = (use_margins ? HOME_Y(pcs) : DEFAULT_Y_START(pcs));
/* if one VMI distance or less remains, always exit */
if ((vmi_cp == 0) || (y <= vmi_cp)) {
y = y0;
break;
}
/* otherwise, round to a multiple of VMI distance */
y += y0 - 1 - ((y - 1) % vmi_cp);
}
pcs->cap.y = y;
}
pcl_continue_underline(pcs);
return 0;
}
static inline float
motion_args(pcl_args_t *pargs, bool truncate)
{
float arg = float_arg(pargs);
if (truncate)
arg = floor(arg);
return arg;
}
/* some convenient short-hand for the cursor movement commands */
static inline void
do_horiz_motion(
pcl_args_t *pargs,
pcl_state_t *pcs,
coord mul,
bool truncate_arg
)
{
pcl_set_cap_x(pcs, (coord)(motion_args(pargs, truncate_arg) * mul), arg_is_signed(pargs), false);
return;
}
static inline int
do_vertical_move(pcl_state_t *pcs, pcl_args_t *pargs, float mul,
bool use_margins, bool by_row, bool by_row_command, bool truncate_arg)
{
return pcl_set_cap_y(pcs, (coord)(motion_args(pargs, truncate_arg) * mul),
arg_is_signed(pargs), use_margins, by_row,
by_row_command);
}
/*
* Control character action implementation.
*
* These routines perform just the individual actions. The control character
* routines may invoke several of these, based on the selected line termination
* setting.
*
* do_CR and do_LF are exported for use by the text manipulation routines and
* the display functions.
*
* Note: CR always "breaks" an underline, even if it is a movement to the right.
*/
void
pcl_do_CR(
pcl_state_t * pcs
)
{
pcl_break_underline(pcs);
pcl_set_cap_x(pcs, pcs->margins.left, false, false);
pcl_continue_underline(pcs);
}
int
pcl_do_LF(
pcl_state_t * pcs
)
{
return pcl_set_cap_y( pcs,
pcs->vmi_cp,
true,
(pcs->perforation_skip == 1),
true,
false
);
}
/*
* Unconditionally feed a page, and move the the "home" verical position on
* the followin page.
*/
int
pcl_do_FF(
pcl_state_t * pcs
)
{
int code = pcl_end_page_always(pcs);
if (code >= 0) {
code = pcl_set_cap_y(pcs, 0L, false, false, true, false);
pcl_continue_underline(pcs); /* (after adjusting y!) */
}
return code;
}
/*
* Return the cursor to its "home" position
*/
void
pcl_home_cursor(
pcl_state_t * pcs
)
{
pcl_set_cap_x(pcs, pcs->margins.left, false, false);
pcl_set_cap_y(pcs, 0L, false, false, true, false);
}
/*
* Update the HMI by recomputing it from the font.
*/
coord
pcl_updated_hmi(
pcl_state_t * pcs
)
{
coord hmi;
const pcl_font_selection_t * pfs =
&(pcs->font_selection[pcs->font_selected]);
int code = pcl_recompute_font(pcs, false);
const pl_font_t * plfont = pcs->font;
if (code < 0)
return pcs->hmi_cp; /* bad news; don't mark the HMI as valid. */
/* we check for typeface == 0 here (lineprinter) because we
frequently simulate lineprinter with a scalable truetype
font */
if (pl_font_is_scalable(plfont) && plfont->params.typeface_family != 0) {
if (plfont->params.proportional_spacing)
/* Scale the font's pitch by the requested height. */
hmi = (coord)(pl_fp_pitch_cp(&plfont->params) / 10.0 * pfs->params.height_4ths / 4);
else
hmi = (coord)pl_fp_pitch_cp(&(pfs->params));
} else
hmi = (coord)pl_fp_pitch_cp(&(plfont->params));
/*
* Round to a multiple of the unit of measure (see the "PCL 5 Printer
* LanguageTechnical Reference Manual", October 1992 ed., page 5-22.
*/
hmi = hmi + pcs->uom_cp / 2;
return pcs->hmi_cp = hmi - (hmi % pcs->uom_cp);
}
/* Commands */
/*
* ESC & k <x> H
*
* Set horizontal motion index.
*/
static int
set_horiz_motion_index(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
/* HMI in 120 units converted to 7200 units with roundup */
pcs->hmi_cp = (coord)((fabs(float_arg(pargs)) * 60.0) + 0.5);
return 0;
}
/*
* ESC & l <y> C
*
* Set vertical motion index.
*
* Contrary to HP's documentation ("PCL 5 Printer Language Technical Reference
* Manual", October 1992 ed., p. 5-24), this command is NOT ignored if the
* requested VMI is greater than the page length.
*
* Apparently this problem has been fixed in the Color Laserjet 4600.
* For the old behavior undefine the next definition.
*/
#define HP_VERT_MOTION_NEW
static int
set_vert_motion_index(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
/* LMI :== 48.0 / lpi; ie 0.16 = 48/300;
* convert to pcl_coord_scale (7200), roundup the float prior to truncation.
*/
coord vcp = (coord)((fabs(float_arg(pargs)) * 7200.0 / 48.0) + 0.5);
#ifdef HP_VERT_MOTION_NEW
if (vcp <= pcs->xfm_state.pd_size.y)
#endif
pcs->vmi_cp = vcp;
return 0;
}
#undef HP_VERT_MOTION_NEW
/*
* ESC & l <lpi> D
*
* Set line spacing. Though it is not documented anywhere, various HP devices
* agree that a zero operand specifies 12 lines per inch (NOT the default).
*/
static int
set_line_spacing(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
uint lpi = uint_arg(pargs);
if (lpi == 0) /* 0 ==> 12 lines per inch */
lpi = 12;
if ((48 % lpi) == 0) /* lpi must divide 48 */
pcs->vmi_cp = inch2coord(1.0 / lpi);
return 0;
}
/*
* ESC & k G
*/
static int
set_line_termination(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
uint ui = uint_arg(pargs);
if (ui <= 3)
pcs->line_termination = ui;
return 0;
}
/*
* ESC & a <cols> C
*/
static int
horiz_cursor_pos_columns(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
do_horiz_motion(pargs, pcs, pcl_hmi(pcs), false);
return 0;
}
/*
* ESC & a <dp> H
*/
static int
horiz_cursor_pos_decipoints(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
do_horiz_motion(pargs, pcs, (coord)10.0, false);
return 0;
}
/*
* ESC * p <units> X
*/
static int
horiz_cursor_pos_units(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
do_horiz_motion(pargs, pcs, pcs->uom_cp, true);
return 0;
}
/*
* CR
*/
static int
cmd_CR(
pcl_args_t * pargs, /* ignored */
pcl_state_t * pcs
)
{
pcl_do_CR(pcs);
return ((pcs->line_termination & 1) != 0 ? pcl_do_LF(pcs) : 0);
}
/*
* BS
*/
static int
cmd_BS(
pcl_args_t * pargs, /* ignored */
pcl_state_t * pcs
)
{
pcl_set_cap_x(pcs, (coord)-pcs->last_width, true, true);
pcs->last_was_BS = true;
return 0;
}
/*
* HT
*
* Tabs occur at ever 8 columns, measure from the left text margin.
*/
static int
cmd_HT(
pcl_args_t * pargs, /* ignored */
pcl_state_t * pcs
)
{
coord x = pcs->cap.x - pcs->margins.left;
coord tab;
if (x < 0)
x = -x;
else if ((tab = 8 * pcl_hmi(pcs)) > 0)
x = tab - (x % tab);
else
x = 0L;
pcl_set_cap_x(pcs, x, true, true);
return 0;
}
/*
* ESC & a <rows> R
*/
static int
vert_cursor_pos_rows(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
return do_vertical_move(pcs, pargs, (float)pcs->vmi_cp, false, true, true, false);
}
/*
* ESC & a <dp> V
*/
static int
vert_cursor_pos_decipoints(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
return do_vertical_move(pcs, pargs, 10.0, false, false, false, false);
}
/*
* ESC * p <units> Y
*/
static int
vert_cursor_pos_units(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
return do_vertical_move(pcs, pargs, (float)pcs->uom_cp, false, false, false, true);
}
/*
* ESC =
*/
static int
half_line_feed(
pcl_args_t * pargs, /* ignored */
pcl_state_t * pcs
)
{
return pcl_set_cap_y( pcs,
pcs->vmi_cp / 2,
true,
(pcs->perforation_skip == 1),
true,
false
);
}
/*
* LF
*/
static int
cmd_LF(
pcl_args_t * pargs, /* ignored */
pcl_state_t * pcs
)
{
if ((pcs->line_termination & 2) != 0)
pcl_do_CR(pcs);
return pcl_do_LF(pcs);
}
/*
* FF
*/
static int
cmd_FF(
pcl_args_t * pargs, /* ignored */
pcl_state_t * pcs
)
{
if ((pcs->line_termination & 2) != 0)
pcl_do_CR(pcs);
return pcl_do_FF(pcs);
}
/*
* ESC & f <pp_enum> S
*
* Contrary to what is indicated in the "PCL 5 Printer Language Technical
* Reference Manual", October 1992 ed., p. 6-16, pushd cursors are stored
* in logical page space, not device space.
*/
static int
push_pop_cursor(
pcl_args_t * pargs,
pcl_state_t * pcs
)
{
int type = uint_arg(pargs);
if ((type == 0) && (pcs->cursor_stk_size < countof(pcs->cursor_stk))) {
gs_point * ppt = &(pcs->cursor_stk[pcs->cursor_stk_size++]);
ppt->x = (double)pcs->cap.x;
ppt->y = (double)pcs->cap.y;
gs_point_transform( ppt->x, ppt->y, &(pcs->xfm_state.pd2lp_mtx), ppt);
} else if ((type == 1) && (pcs->cursor_stk_size > 0)) {
gs_point * ppt = &(pcs->cursor_stk[--pcs->cursor_stk_size]);
gs_matrix lp2pd;
pcl_invert_mtx(&(pcs->xfm_state.pd2lp_mtx), &lp2pd);
gs_point_transform(ppt->x, ppt->y, &lp2pd, ppt);
pcl_set_cap_x(pcs, (coord)ppt->x, false, false);
pcl_set_cap_y( pcs,
(coord)ppt->y - pcs->margins.top,
false,
false,
false,
false
);
}
return 0;
}
static int
pcursor_do_copy(pcl_state_t *psaved,
const pcl_state_t *pcs, pcl_copy_operation_t operation)
{
int i;
/* don't restore the current cap. The cap is not part of the
state */
if ( operation & pcl_copy_after ) {
psaved->cap = pcs->cap;
/* cursor stack isn't part of the state, either */
for (i = 0; i < pcs->cursor_stk_size; ++i) {
psaved->cursor_stk[i] = pcs->cursor_stk[i];
}
psaved->cursor_stk_size = pcs->cursor_stk_size;
/* NB doesn't belong here */
psaved->page_marked = pcs->page_marked;
}
return 0;
}
/*
* Initialization
*/
static int
pcursor_do_registration(
pcl_parser_state_t *pcl_parser_state,
gs_memory_t * pmem
)
{
DEFINE_CLASS('&')
{
'k', 'H',
PCL_COMMAND( "Horizontal Motion Index",
set_horiz_motion_index,
pca_neg_ok | pca_big_clamp
)
},
{
'l', 'C',
PCL_COMMAND( "Vertical Motion Index",
set_vert_motion_index,
pca_neg_ok | pca_big_ignore
)
},
{
'l', 'D',
PCL_COMMAND( "Line Spacing",
set_line_spacing,
pca_neg_ok | pca_big_ignore
)
},
{
'k', 'G',
PCL_COMMAND( "Line Termination",
set_line_termination,
pca_neg_ok | pca_big_ignore
)
},
{
'a', 'C',
PCL_COMMAND( "Horizontal Cursor Position Columns",
horiz_cursor_pos_columns,
pca_neg_ok | pca_big_ok
)
},
{
'a', 'H',
PCL_COMMAND( "Horizontal Cursor Position Decipoints",
horiz_cursor_pos_decipoints,
pca_neg_ok | pca_big_ok
)
},
{
'a', 'R',
PCL_COMMAND( "Vertical Cursor Position Rows",
vert_cursor_pos_rows,
pca_neg_ok | pca_big_clamp
)
},
{
'a', 'V',
PCL_COMMAND( "Vertical Cursor Position Decipoints",
vert_cursor_pos_decipoints,
pca_neg_ok | pca_big_ok
)
},
{
'f', 'S',
PCL_COMMAND( "Push/Pop Cursor",
push_pop_cursor,
pca_neg_ok | pca_big_ignore
)
},
END_CLASS
DEFINE_CLASS('*')
{
'p', 'X',
PCL_COMMAND( "Horizontal Cursor Position Units",
horiz_cursor_pos_units,
pca_neg_ok | pca_big_ok | pca_in_rtl
)
},
{
'p', 'Y',
PCL_COMMAND( "Vertical Cursor Position Units",
vert_cursor_pos_units,
pca_neg_ok | pca_big_ok | pca_in_rtl
)
},
END_CLASS
DEFINE_CONTROL(CR, "CR", cmd_CR)
DEFINE_CONTROL(BS, "BS", cmd_BS)
DEFINE_CONTROL(HT, "HT", cmd_HT)
DEFINE_ESCAPE('=', "Half Line Feed", half_line_feed)
DEFINE_CONTROL(LF, "LF", cmd_LF)
DEFINE_CONTROL(FF, "FF", cmd_FF)
return 0;
}
static void
pcursor_do_reset(
pcl_state_t * pcs,
pcl_reset_type_t type
)
{
static const uint mask = ( pcl_reset_initial
| pcl_reset_printer
| pcl_reset_overlay );
if ((type & mask) == 0)
return;
pcs->line_termination = 0;
pcs->hmi_cp = HMI_DEFAULT;
pcs->vmi_cp = pcs->margins.length
/ pjl_proc_vartoi(pcs->pjls, pjl_proc_get_envvar(pcs->pjls, "formlines"));
if ( (type & pcl_reset_overlay) == 0 ) {
pcs->cursor_stk_size = 0;
/*
* If this is an initial reset, make sure underlining is
* disabled (homing the cursor may cause an underline to be
* put out. And provide reasonable initial values for the
* cap.
*/
if ((type & pcl_reset_initial) != 0) {
pcs->underline_enabled = false;
pcs->cap.x = pcs->cap.y = 0;
}
}
pcl_home_cursor(pcs);
}
const pcl_init_t pcursor_init = { pcursor_do_registration, pcursor_do_reset, pcursor_do_copy };
|