2 * Copyright (C) 2012, The AROS Development Team. All rights reserved.
3 * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
5 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
12 #include <aros/debug.h>
14 #include "printer_intern.h"
19 #define FLUSH_BUFFER() \
22 pd->pd_PWrite(buffer, blen); \
24 buffer = buff[buffsel]; \
31 #define CSI_BRACK_SEMI ';'
32 #define CSI_BRACK_QUOTE '"'
44 static const struct StateTable StateTable
[] = {
45 { .state
= 0, .code
= 0, .parm
= -1, .cmd
= -1 },
46 { .state
= CSI
, .code
= 'D', .parm
= -1, .cmd
= aIND
},
47 { .state
= CSI
, .code
= 'E', .parm
= -1, .cmd
= aNEL
},
48 { .state
= CSI
, .code
= 'H', .parm
= -1, .cmd
= aHTS
},
49 { .state
= CSI
, .code
= 'J', .parm
= -1, .cmd
= aVTS
},
50 { .state
= CSI
, .code
= 'K', .parm
= -1, .cmd
= aPLD
},
51 { .state
= CSI
, .code
= 'L', .parm
= -1, .cmd
= aPLU
},
52 { .state
= CSI
, .code
= 'M', .parm
= -1, .cmd
= aRI
},
53 { .state
= CSI
, .code
= 'c', .parm
= -1, .cmd
= aRIS
},
54 { .state
= CSI_HASH
, .code
= '0', .parm
= -1, .cmd
= aRMS
},
55 { .state
= CSI_HASH
, .code
= '1', .parm
= -1, .cmd
= aRIN
},
56 { .state
= CSI_HASH
, .code
= '2', .parm
= -1, .cmd
= aBMS
},
57 { .state
= CSI_HASH
, .code
= '3', .parm
= -1, .cmd
= aCAM
},
58 { .state
= CSI_HASH
, .code
= '4', .parm
= -1, .cmd
= aTBCALL
},
59 { .state
= CSI_HASH
, .code
= '5', .parm
= -1, .cmd
= aTBSALL
},
60 { .state
= CSI_HASH
, .code
= '8', .parm
= -1, .cmd
= aTMS
},
61 { .state
= CSI_HASH
, .code
= '9', .parm
= -1, .cmd
= aLMS
},
62 { .state
= CSI_PAREN
, .code
= '6', .parm
= -1, .cmd
= aFNT9
},
63 { .state
= CSI_PAREN
, .code
= 'A', .parm
= -1, .cmd
= aFNT3
},
64 { .state
= CSI_PAREN
, .code
= 'B', .parm
= -1, .cmd
= aFNT0
},
65 { .state
= CSI_PAREN
, .code
= 'C', .parm
= -1, .cmd
= aFNT10
},
66 { .state
= CSI_PAREN
, .code
= 'E', .parm
= -1, .cmd
= aFNT4
},
67 { .state
= CSI_PAREN
, .code
= 'H', .parm
= -1, .cmd
= aFNT5
},
68 { .state
= CSI_PAREN
, .code
= 'J', .parm
= -1, .cmd
= aFNT8
},
69 { .state
= CSI_PAREN
, .code
= 'K', .parm
= -1, .cmd
= aFNT2
},
70 { .state
= CSI_PAREN
, .code
= 'R', .parm
= -1, .cmd
= aFNT1
},
71 { .state
= CSI_PAREN
, .code
= 'Y', .parm
= -1, .cmd
= aFNT6
},
72 { .state
= CSI_PAREN
, .code
= 'Z', .parm
= -1, .cmd
= aFNT7
},
73 { .state
= CSI_BRACK
, .code
= 'E', .parm
= -1, .cmd
= aTSS
},
74 { .state
= CSI_BRACK
, .code
= 'F', .parm
= 0, .cmd
= aJFY0
},
75 { .state
= CSI_BRACK
, .code
= 'F', .parm
= 1, .cmd
= aJFY1
},
76 { .state
= CSI_BRACK
, .code
= 'F', .parm
= 3, .cmd
= aJFY3
},
77 { .state
= CSI_BRACK
, .code
= 'F', .parm
= 5, .cmd
= aJFY5
},
78 { .state
= CSI_BRACK
, .code
= 'F', .parm
= 6, .cmd
= aJFY6
},
79 { .state
= CSI_BRACK
, .code
= 'F', .parm
= 7, .cmd
= aJFY7
},
80 { .state
= CSI_BRACK
, .code
= 'g', .parm
= 0, .cmd
= aTBC0
},
81 { .state
= CSI_BRACK
, .code
= 'g', .parm
= 1, .cmd
= aTBC1
},
82 { .state
= CSI_BRACK
, .code
= 'g', .parm
= 3, .cmd
= aTBC3
},
83 { .state
= CSI_BRACK
, .code
= 'g', .parm
= 4, .cmd
= aTBC4
},
84 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 0, .cmd
= aSGR0
},
85 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 1, .cmd
= aSGR1
},
86 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 22, .cmd
= aSGR22
},
87 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 23, .cmd
= aSGR23
},
88 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 24, .cmd
= aSGR24
},
89 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 3, .cmd
= aSGR3
},
90 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 30, .cmd
= aSFC
},
91 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 31, .cmd
= aSFC
},
92 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 32, .cmd
= aSFC
},
93 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 33, .cmd
= aSFC
},
94 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 34, .cmd
= aSFC
},
95 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 35, .cmd
= aSFC
},
96 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 36, .cmd
= aSFC
},
97 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 37, .cmd
= aSFC
},
98 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 38, .cmd
= aSFC
},
99 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 39, .cmd
= aSFC
},
100 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 4, .cmd
= aSGR4
},
101 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 40, .cmd
= aSBC
},
102 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 41, .cmd
= aSBC
},
103 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 42, .cmd
= aSBC
},
104 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 43, .cmd
= aSBC
},
105 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 44, .cmd
= aSBC
},
106 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 45, .cmd
= aSBC
},
107 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 46, .cmd
= aSBC
},
108 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 47, .cmd
= aSBC
},
109 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 48, .cmd
= aSBC
},
110 { .state
= CSI_BRACK
, .code
= 'm', .parm
= 49, .cmd
= aSBC
},
111 { .state
= CSI_BRACK
, .code
= 'p', .parm
= 0, .cmd
= aPROP0
},
112 { .state
= CSI_BRACK
, .code
= 'p', .parm
= 1, .cmd
= aPROP1
},
113 { .state
= CSI_BRACK
, .code
= 'p', .parm
= 2, .cmd
= aPROP2
},
114 { .state
= CSI_BRACK
, .code
= 'q', .parm
= -1, .cmd
= aPERF
},
115 { .state
= CSI_BRACK
, .code
= 'q', .parm
= 0, .cmd
= aPERF0
},
116 { .state
= CSI_BRACK
, .code
= 't', .parm
= -1, .cmd
= aSLPP
},
117 { .state
= CSI_BRACK
, .code
= 'v', .parm
= 0, .cmd
= aSUS0
},
118 { .state
= CSI_BRACK
, .code
= 'v', .parm
= 1, .cmd
= aSUS1
},
119 { .state
= CSI_BRACK
, .code
= 'v', .parm
= 2, .cmd
= aSUS2
},
120 { .state
= CSI_BRACK
, .code
= 'v', .parm
= 3, .cmd
= aSUS3
},
121 { .state
= CSI_BRACK
, .code
= 'v', .parm
= 4, .cmd
= aSUS4
},
122 { .state
= CSI_BRACK
, .code
= 'w', .parm
= 0, .cmd
= aSHORP0
},
123 { .state
= CSI_BRACK
, .code
= 'w', .parm
= 1, .cmd
= aSHORP1
},
124 { .state
= CSI_BRACK
, .code
= 'w', .parm
= 2, .cmd
= aSHORP2
},
125 { .state
= CSI_BRACK
, .code
= 'w', .parm
= 3, .cmd
= aSHORP3
},
126 { .state
= CSI_BRACK
, .code
= 'w', .parm
= 4, .cmd
= aSHORP4
},
127 { .state
= CSI_BRACK
, .code
= 'w', .parm
= 5, .cmd
= aSHORP5
},
128 { .state
= CSI_BRACK
, .code
= 'w', .parm
= 6, .cmd
= aSHORP6
},
129 { .state
= CSI_BRACK
, .code
= 'z', .parm
= 0, .cmd
= aVERP0
},
130 { .state
= CSI_BRACK
, .code
= 'z', .parm
= 1, .cmd
= aVERP1
},
131 { .state
= CSI_BRACK_QUOTE
, .code
= 'r', .parm
= -1, .cmd
= aRAW
},
132 { .state
= CSI_BRACK_QUOTE
, .code
= 'x', .parm
= -1, .cmd
= aEXTEND
},
133 { .state
= CSI_BRACK_QUOTE
, .code
= 'z', .parm
= 1, .cmd
= aDEN1
},
134 { .state
= CSI_BRACK_QUOTE
, .code
= 'z', .parm
= 2, .cmd
= aDEN2
},
135 { .state
= CSI_BRACK_QUOTE
, .code
= 'z', .parm
= 3, .cmd
= aDEN3
},
136 { .state
= CSI_BRACK_QUOTE
, .code
= 'z', .parm
= 4, .cmd
= aDEN4
},
137 { .state
= CSI_BRACK_QUOTE
, .code
= 'z', .parm
= 5, .cmd
= aDEN5
},
138 { .state
= CSI_BRACK_QUOTE
, .code
= 'z', .parm
= 6, .cmd
= aDEN6
},
139 { .state
= CSI_BRACK_SEMI
, .code
= 'r', .parm
= -1, .cmd
= aSTBM
},
140 { .state
= CSI_BRACK_SEMI
, .code
= 's', .parm
= -1, .cmd
= aSLRM
},
141 { .state
= CSI_END
},
144 static inline int isdigit(int x
)
146 return (x
>= '0' && x
<= '9');
150 LONG
Printer_Text_Command(struct PrinterData
*pd
, UWORD command
, UBYTE p0
, UBYTE p1
, UBYTE p2
, UBYTE p3
)
152 struct PrinterExtendedData
*ped
= &pd
->pd_SegmentData
->ps_PED
;
153 struct PrinterUnitText
*txt
= &pd
->pd_PUnit
->pu_Text
;
154 CONST_STRPTR
*Commands
= pd
->pd_Device
.dd_CmdVectors
;
155 LONG CommandMax
= pd
->pd_Device
.dd_NumCommands
;
156 /* Use pd_Stack as the command buffer */
157 /* pd_OldStk[8..11] is used for the 'TPMATCHWORD' magic
159 UBYTE
*buff
[2] = { (UBYTE
*)&pd
->pd_Stk
[0], (UBYTE
*)&pd
->pd_OldStk
[12] };
161 UBYTE
*buffer
= buff
[buffsel
];
162 LONG buffmax
= ((P_STKSIZE
> (P_OLDSTKSIZE
-12)) ? (P_OLDSTKSIZE
-12) : P_STKSIZE
)/2;
165 UBYTE parm
[4] = { p0
, p1
, p2
, p3
};
167 if (command
>= CommandMax
)
170 cmd
= Commands
[command
];
172 D(bug("%s: cmd=%d(%s), (%d, %d, %d, %d)\n", __func__
, command
, cmd
, p0
, p1
, p2
, p3
));
177 if (command
== aRIN
|| command
== aRIS
) {
178 txt
->pt_CurrentLine
= 0;
180 txt
->pt_Spacing
= pd
->pd_Preferences
.PrintSpacing
;
183 for (; *cmd
; cmd
++) {
184 D(bug("%s: command=%d '%c'(%d), ped_DoSpecial=%p \n", __func__
, command
, *cmd
, *cmd
, ped
->ped_DoSpecial
));
186 if ((TEXT
)*cmd
== (TEXT
)'\377' && ped
->ped_DoSpecial
) {
189 if ((TEXT
)cmd
[1] == (TEXT
)'\377') {
190 /* NOTE: From printer.device 44.12: flush before calling DoSpecial */
194 err
= ped
->ped_DoSpecial(&command
, &buffer
[blen
], &txt
->pt_CurrentLine
, &txt
->pt_Spacing
, &txt
->pt_CRLF
, parm
);
195 D(bug("%s: ped_DoSpecial: cmd => %d, buf='%s', err=%d\n", __func__
, command
, &buffer
[blen
], err
));
198 } else if (err
== -2) {
200 } else if (err
== 0) {
201 buffer
[blen
++] = *cmd
;
206 buffer
[blen
++] = *cmd
;
209 if (blen
>= buffmax
) {
218 LONG
noopConvFunc(UBYTE
*buf
, UBYTE c
, LONG crlf_flag
)
224 * -1 if not in a command string
225 * -2 if processing a possible command,
226 * >= 0 if a command found
228 static LONG
doState(UBYTE
*state
, UBYTE c
, UBYTE
*parm
, UBYTE
*parm_index
)
230 const struct StateTable
*loc
= &StateTable
[*state
];
231 BYTE currstate
= loc
->state
;
233 if (currstate
== 0) {
242 if (currstate
!= 0 && currstate
!= CSI
&& currstate
!= CSI_HASH
) {
244 UWORD p
= parm
[*parm_index
];
246 p
= (p
* 10) + (c
- '0');
251 parm
[*parm_index
] = (UBYTE
)p
;
256 /* State promotion */
257 if ((currstate
== CSI
&& (c
== CSI_HASH
|| c
== CSI_PAREN
|| c
== CSI_BRACK
)) ||
258 (currstate
== CSI_BRACK
&& (c
== CSI_BRACK_SEMI
|| c
== CSI_BRACK_QUOTE
))) {
259 /* Advance to next matching state */
260 for (; loc
->state
!= CSI_END
&& loc
->state
!= c
; loc
++, (*state
)++);
261 if (loc
->state
== CSI_END
) {
266 if (c
== CSI_BRACK_SEMI
) {
267 parm
[++(*parm_index
)]=0;
273 for (; loc
->state
== currstate
&& loc
->code
!= c
; loc
++, (*state
)++);
275 if (loc
->state
!= currstate
) {
281 for (; loc
->state
== currstate
; loc
++, (*state
)++) {
282 if ((loc
->parm
== -1) || (loc
->parm
== parm
[0])) {
293 LONG
Printer_Text_Write(struct PrinterData
*pd
, UBYTE
*text
, LONG length
)
295 struct PrinterExtendedData
*ped
= &pd
->pd_SegmentData
->ps_PED
;
296 struct PrinterUnitText
*txt
= &pd
->pd_PUnit
->pu_Text
;
297 LONG (*ConvFunc
)(UBYTE
*buf
, UBYTE c
, LONG crlf_flag
);
298 CONST_STRPTR
*Char8Bit
= NULL
;
302 UBYTE buff
[2][WBUFSIZE
];
303 UBYTE
*buffer
= &buff
[0][0];
308 if (pd
->pd_SegmentData
->ps_Version
>= 33) {
309 Char8Bit
= (CONST_STRPTR
*)ped
->ped_8BitChars
;
312 if (pd
->pd_SegmentData
->ps_Version
>= 34) {
313 ConvFunc
= ped
->ped_ConvFunc
;
315 ConvFunc
= noopConvFunc
;
318 for (;(length
< 0 && *text
) || (length
> 0); text
++, length
--) {
320 D(bug("%s: c='%c' (\\%o)\n", __func__
, *text
, *text
));
321 cmd
= doState(&state
, *text
, parm
, &pindex
);
326 if (Char8Bit
&& *text
>= 0xa0) {
327 CONST_STRPTR str
= Char8Bit
[*text
-0xa0];
328 pd
->pd_PWrite((APTR
)str
, strlen(str
));
331 err
= ConvFunc(&buffer
[blen
], *text
, txt
->pt_CRLF
);
332 D(bug("%s: ConvFunc(%d) => %d\n", __func__
, *text
, err
));
336 Printer_Text_Command(pd
, aNEL
, 0, 0, 0, 0);
338 buffer
[blen
++] = *text
;
345 Printer_Text_Command(pd
, cmd
, parm
[0], parm
[1], parm
[2], parm
[3]);
348 if (blen
> WBUFSIZE
/2)