1 | /* $NetBSD: wsemul_vt100_subr.c,v 1.20 2010/02/10 19:39:39 drochner Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1998 |
5 | * Matthias Drochner. All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * |
27 | */ |
28 | |
29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: wsemul_vt100_subr.c,v 1.20 2010/02/10 19:39:39 drochner Exp $" ); |
31 | |
32 | #include <sys/param.h> |
33 | #include <sys/systm.h> |
34 | |
35 | #include <dev/wscons/wsconsio.h> |
36 | #include <dev/wscons/wsksymvar.h> |
37 | #include <dev/wscons/wsdisplayvar.h> |
38 | #include <dev/wscons/wsemulvar.h> |
39 | #include <dev/wscons/vt100_base.h> |
40 | |
41 | #include "opt_wsemul.h" |
42 | |
43 | static int vt100_selectattribute(struct vt100base_data *, |
44 | int, int, int, long *, long *); |
45 | static int vt100_ansimode(struct vt100base_data *, int, int); |
46 | static int vt100_decmode(struct vt100base_data *, int, int); |
47 | #define VTMODE_SET 33 |
48 | #define VTMODE_RESET 44 |
49 | #define VTMODE_REPORT 55 |
50 | |
51 | /* |
52 | * scroll up within scrolling region |
53 | */ |
54 | void |
55 | wsemul_vt100_scrollup(struct vt100base_data *edp, int n) |
56 | { |
57 | int help; |
58 | |
59 | if (n > edp->scrreg_nrows) |
60 | n = edp->scrreg_nrows; |
61 | |
62 | help = edp->scrreg_nrows - n; |
63 | if (help > 0) { |
64 | (*edp->emulops->copyrows)(edp->emulcookie, |
65 | edp->scrreg_startrow + n, |
66 | edp->scrreg_startrow, |
67 | help); |
68 | if (edp->dblwid) |
69 | memmove(&edp->dblwid[edp->scrreg_startrow], |
70 | &edp->dblwid[edp->scrreg_startrow + n], |
71 | help); |
72 | } |
73 | (*edp->emulops->eraserows)(edp->emulcookie, |
74 | edp->scrreg_startrow + help, n, |
75 | edp->bkgdattr); |
76 | if (edp->dblwid) |
77 | memset(&edp->dblwid[edp->scrreg_startrow + help], 0, n); |
78 | CHECK_DW(edp); |
79 | } |
80 | |
81 | /* |
82 | * scroll down within scrolling region |
83 | */ |
84 | void |
85 | wsemul_vt100_scrolldown(struct vt100base_data *edp, int n) |
86 | { |
87 | int help; |
88 | |
89 | if (n > edp->scrreg_nrows) |
90 | n = edp->scrreg_nrows; |
91 | |
92 | help = edp->scrreg_nrows - n; |
93 | if (help > 0) { |
94 | (*edp->emulops->copyrows)(edp->emulcookie, |
95 | edp->scrreg_startrow, |
96 | edp->scrreg_startrow + n, |
97 | help); |
98 | if (edp->dblwid) |
99 | memmove(&edp->dblwid[edp->scrreg_startrow + n], |
100 | &edp->dblwid[edp->scrreg_startrow], |
101 | help); |
102 | } |
103 | (*edp->emulops->eraserows)(edp->emulcookie, |
104 | edp->scrreg_startrow, n, |
105 | edp->bkgdattr); |
106 | if (edp->dblwid) |
107 | memset(&edp->dblwid[edp->scrreg_startrow], 0, n); |
108 | CHECK_DW(edp); |
109 | } |
110 | |
111 | /* |
112 | * erase in display |
113 | */ |
114 | void |
115 | wsemul_vt100_ed(struct vt100base_data *edp, int arg) |
116 | { |
117 | int n; |
118 | |
119 | switch (arg) { |
120 | case 0: /* cursor to end */ |
121 | ERASECOLS(edp, edp->ccol, COLS_LEFT(edp) + 1, edp->bkgdattr); |
122 | n = edp->nrows - edp->crow - 1; |
123 | if (n > 0) { |
124 | (*edp->emulops->eraserows)(edp->emulcookie, |
125 | edp->crow + 1, n, |
126 | edp->bkgdattr); |
127 | if (edp->dblwid) |
128 | memset(&edp->dblwid[edp->crow + 1], 0, n); |
129 | } |
130 | break; |
131 | case 1: /* beginning to cursor */ |
132 | if (edp->crow > 0) { |
133 | (*edp->emulops->eraserows)(edp->emulcookie, |
134 | 0, edp->crow, |
135 | edp->bkgdattr); |
136 | if (edp->dblwid) |
137 | memset(&edp->dblwid[0], 0, edp->crow); |
138 | } |
139 | ERASECOLS(edp, 0, edp->ccol + 1, edp->bkgdattr); |
140 | break; |
141 | case 2: /* complete display */ |
142 | (*edp->emulops->eraserows)(edp->emulcookie, |
143 | 0, edp->nrows, |
144 | edp->bkgdattr); |
145 | if (edp->dblwid) |
146 | memset(&edp->dblwid[0], 0, edp->nrows); |
147 | break; |
148 | default: |
149 | #ifdef VT100_PRINTUNKNOWN |
150 | printf("ed(%d) unknown\n" , arg); |
151 | #endif |
152 | break; |
153 | } |
154 | CHECK_DW(edp); |
155 | } |
156 | |
157 | /* |
158 | * erase in line |
159 | */ |
160 | void |
161 | wsemul_vt100_el(struct vt100base_data *edp, int arg) |
162 | { |
163 | switch (arg) { |
164 | case 0: /* cursor to end */ |
165 | ERASECOLS(edp, edp->ccol, COLS_LEFT(edp) + 1, edp->bkgdattr); |
166 | break; |
167 | case 1: /* beginning to cursor */ |
168 | ERASECOLS(edp, 0, edp->ccol + 1, edp->bkgdattr); |
169 | break; |
170 | case 2: /* complete line */ |
171 | (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, |
172 | 0, edp->ncols, |
173 | edp->bkgdattr); |
174 | break; |
175 | default: |
176 | #ifdef VT100_PRINTUNKNOWN |
177 | printf("el(%d) unknown\n" , arg); |
178 | #endif |
179 | break; |
180 | } |
181 | } |
182 | |
183 | /* |
184 | * handle commands after CSI (ESC[) |
185 | */ |
186 | void |
187 | wsemul_vt100_handle_csi(struct vt100base_data *edp, u_char c) |
188 | { |
189 | int n, help, flags, fgcol, bgcol; |
190 | long attr, bkgdattr; |
191 | |
192 | #define A3(a, b, c) (((a) << 16) | ((b) << 8) | (c)) |
193 | switch (A3(edp->modif1, edp->modif2, c)) { |
194 | case A3('>', '\0', 'c'): /* DA secondary */ |
195 | wsdisplay_emulinput(edp->cbcookie, WSEMUL_VT_ID2, |
196 | sizeof(WSEMUL_VT_ID2)); |
197 | break; |
198 | |
199 | case A3('\0', '\0', 'J'): /* ED selective erase in display */ |
200 | case A3('?', '\0', 'J'): /* DECSED selective erase in display */ |
201 | wsemul_vt100_ed(edp, ARG(edp, 0)); |
202 | break; |
203 | case A3('\0', '\0', 'K'): /* EL selective erase in line */ |
204 | case A3('?', '\0', 'K'): /* DECSEL selective erase in line */ |
205 | wsemul_vt100_el(edp, ARG(edp, 0)); |
206 | break; |
207 | case A3('\0', '\0', 'h'): /* SM */ |
208 | for (n = 0; n < edp->nargs; n++) |
209 | vt100_ansimode(edp, ARG(edp, n), VTMODE_SET); |
210 | break; |
211 | case A3('?', '\0', 'h'): /* DECSM */ |
212 | for (n = 0; n < edp->nargs; n++) |
213 | vt100_decmode(edp, ARG(edp, n), VTMODE_SET); |
214 | break; |
215 | case A3('\0', '\0', 'l'): /* RM */ |
216 | for (n = 0; n < edp->nargs; n++) |
217 | vt100_ansimode(edp, ARG(edp, n), VTMODE_RESET); |
218 | break; |
219 | case A3('?', '\0', 'l'): /* DECRM */ |
220 | for (n = 0; n < edp->nargs; n++) |
221 | vt100_decmode(edp, ARG(edp, n), VTMODE_RESET); |
222 | break; |
223 | case A3('\0', '$', 'p'): /* DECRQM request mode ANSI */ |
224 | vt100_ansimode(edp, ARG(edp, 0), VTMODE_REPORT); |
225 | break; |
226 | case A3('?', '$', 'p'): /* DECRQM request mode DEC */ |
227 | vt100_decmode(edp, ARG(edp, 0), VTMODE_REPORT); |
228 | break; |
229 | case A3('\0', '\0', 'i'): /* MC printer controller mode */ |
230 | case A3('?', '\0', 'i'): /* MC printer controller mode */ |
231 | switch (ARG(edp, 0)) { |
232 | case 0: /* print screen */ |
233 | case 1: /* print cursor line */ |
234 | case 4: /* off */ |
235 | case 5: /* on */ |
236 | #ifdef VT100_PRINTNOTIMPL |
237 | printf("CSI%di ignored\n" , ARG(edp, 0)); |
238 | #endif |
239 | break; |
240 | default: |
241 | #ifdef VT100_PRINTUNKNOWN |
242 | printf("CSI%di unknown\n" , ARG(edp, 0)); |
243 | #endif |
244 | break; |
245 | } |
246 | break; |
247 | |
248 | #define A2(a, b) (((a) << 8) | (b)) |
249 | #if 0 /* XXX */ |
250 | case A2('!', 'p'): /* DECSTR soft reset VT300 only */ |
251 | wsemul_vt100_reset(edp); |
252 | break; |
253 | #endif |
254 | |
255 | case A2('"', 'p'): /* DECSCL */ |
256 | switch (ARG(edp, 0)) { |
257 | case 61: /* VT100 mode (no further arguments!) */ |
258 | break; |
259 | case 62: |
260 | case 63: /* VT300 mode */ |
261 | break; |
262 | default: |
263 | #ifdef VT100_PRINTUNKNOWN |
264 | printf("CSI%d\"p unknown\n" , ARG(edp, 0)); |
265 | #endif |
266 | break; |
267 | } |
268 | switch (ARG(edp, 1)) { |
269 | case 0: |
270 | case 2: /* 8-bit controls */ |
271 | #ifdef VT100_PRINTNOTIMPL |
272 | printf("CSI%d;%d\"p ignored\n" , ARG(edp, 0), ARG(edp, 1)); |
273 | #endif |
274 | break; |
275 | case 1: /* 7-bit controls */ |
276 | break; |
277 | default: |
278 | #ifdef VT100_PRINTUNKNOWN |
279 | printf("CSI%d;%d\"p unknown\n" , ARG(edp, 0), ARG(edp, 1)); |
280 | #endif |
281 | break; |
282 | } |
283 | break; |
284 | case A2('"', 'q'): /* DECSCA select character attribute VT300 */ |
285 | switch (ARG(edp, 0)) { |
286 | case 0: |
287 | case 1: /* erasable */ |
288 | break; |
289 | case 2: /* not erasable */ |
290 | #ifdef VT100_PRINTNOTIMPL |
291 | printf("CSI2\"q ignored\n" ); |
292 | #endif |
293 | break; |
294 | default: |
295 | #ifdef VT100_PRINTUNKNOWN |
296 | printf("CSI%d\"q unknown\n" , ARG(edp, 0)); |
297 | #endif |
298 | break; |
299 | } |
300 | break; |
301 | |
302 | case A2('$', 'u'): /* DECRQTSR request terminal status report */ |
303 | switch (ARG(edp, 0)) { |
304 | case 0: /* ignored */ |
305 | break; |
306 | case 1: /* terminal state report */ |
307 | #ifdef VT100_PRINTNOTIMPL |
308 | printf("CSI1$u ignored\n" ); |
309 | #endif |
310 | break; |
311 | default: |
312 | #ifdef VT100_PRINTUNKNOWN |
313 | printf("CSI%d$u unknown\n" , ARG(edp, 0)); |
314 | #endif |
315 | break; |
316 | } |
317 | break; |
318 | case A2('$', 'w'): /* DECRQPSR request presentation status report |
319 | (VT300 only) */ |
320 | switch (ARG(edp, 0)) { |
321 | case 0: /* error */ |
322 | break; |
323 | case 1: /* cursor information report */ |
324 | #ifdef VT100_PRINTNOTIMPL |
325 | printf("CSI1$w ignored\n" ); |
326 | #endif |
327 | break; |
328 | case 2: /* tab stop report */ |
329 | { |
330 | int i, j, ps = 0; |
331 | char buf[20]; |
332 | KASSERT(edp->tabs != 0); |
333 | wsdisplay_emulinput(edp->cbcookie, "\033P2$u" , 5); |
334 | for (i = 0; i < edp->ncols; i++) |
335 | if (edp->tabs[i]) { |
336 | j = snprintf(buf, sizeof(buf), "%s%d" , |
337 | (ps ? "/" : "" ), i + 1); |
338 | wsdisplay_emulinput(edp->cbcookie, |
339 | buf, j); |
340 | ps = 1; |
341 | } |
342 | } |
343 | wsdisplay_emulinput(edp->cbcookie, "\033\\" , 2); |
344 | break; |
345 | default: |
346 | #ifdef VT100_PRINTUNKNOWN |
347 | printf("CSI%d$w unknown\n" , ARG(edp, 0)); |
348 | #endif |
349 | break; |
350 | } |
351 | break; |
352 | case A2('$', '}'): /* DECSASD select active status display */ |
353 | switch (ARG(edp, 0)) { |
354 | case 0: /* main display */ |
355 | case 1: /* status line */ |
356 | #ifdef VT100_PRINTNOTIMPL |
357 | printf("CSI%d$} ignored\n" , ARG(edp, 0)); |
358 | #endif |
359 | break; |
360 | default: |
361 | #ifdef VT100_PRINTUNKNOWN |
362 | printf("CSI%d$} unknown\n" , ARG(edp, 0)); |
363 | #endif |
364 | break; |
365 | } |
366 | break; |
367 | case A2('$', '~'): /* DECSSDD select status line type */ |
368 | switch (ARG(edp, 0)) { |
369 | case 0: /* none */ |
370 | case 1: /* indicator */ |
371 | case 2: /* host-writable */ |
372 | #ifdef VT100_PRINTNOTIMPL |
373 | printf("CSI%d$~ ignored\n" , ARG(edp, 0)); |
374 | #endif |
375 | break; |
376 | default: |
377 | #ifdef VT100_PRINTUNKNOWN |
378 | printf("CSI%d$~ unknown\n" , ARG(edp, 0)); |
379 | #endif |
380 | break; |
381 | } |
382 | break; |
383 | |
384 | case A2('&', 'u'): /* DECRQUPSS request user preferred |
385 | supplemental set */ |
386 | wsdisplay_emulinput(edp->cbcookie, "\033P0!u%5\033\\" , 9); |
387 | break; |
388 | |
389 | case '@': /* ICH insert character VT300 only */ |
390 | n = min(DEF1_ARG(edp, 0), COLS_LEFT(edp) + 1); |
391 | help = NCOLS(edp) - (edp->ccol + n); |
392 | if (help > 0) |
393 | COPYCOLS(edp, edp->ccol, edp->ccol + n, help); |
394 | ERASECOLS(edp, edp->ccol, n, edp->bkgdattr); |
395 | break; |
396 | case 'A': /* CUU */ |
397 | edp->crow -= min(DEF1_ARG(edp, 0), ROWS_ABOVE(edp)); |
398 | CHECK_DW(edp); |
399 | break; |
400 | case 'B': /* CUD */ |
401 | edp->crow += min(DEF1_ARG(edp, 0), ROWS_BELOW(edp)); |
402 | CHECK_DW(edp); |
403 | break; |
404 | case 'C': /* CUF */ |
405 | edp->ccol += min(DEF1_ARG(edp, 0), COLS_LEFT(edp)); |
406 | break; |
407 | case 'D': /* CUB */ |
408 | edp->ccol -= min(DEF1_ARG(edp, 0), edp->ccol); |
409 | edp->flags &= ~VTFL_LASTCHAR; |
410 | break; |
411 | case 'H': /* CUP */ |
412 | case 'f': /* HVP */ |
413 | if (edp->flags & VTFL_DECOM) |
414 | edp->crow = edp->scrreg_startrow + |
415 | min(DEF1_ARG(edp, 0), edp->scrreg_nrows) - 1; |
416 | else |
417 | edp->crow = min(DEF1_ARG(edp, 0), edp->nrows) - 1; |
418 | CHECK_DW(edp); |
419 | edp->ccol = min(DEF1_ARG(edp, 1), NCOLS(edp)) - 1; |
420 | edp->flags &= ~VTFL_LASTCHAR; |
421 | break; |
422 | case 'L': /* IL insert line */ |
423 | case 'M': /* DL delete line */ |
424 | n = min(DEF1_ARG(edp, 0), ROWS_BELOW(edp) + 1); |
425 | { |
426 | int savscrstartrow, savscrnrows; |
427 | savscrstartrow = edp->scrreg_startrow; |
428 | savscrnrows = edp->scrreg_nrows; |
429 | edp->scrreg_nrows -= ROWS_ABOVE(edp); |
430 | edp->scrreg_startrow = edp->crow; |
431 | if (c == 'L') |
432 | wsemul_vt100_scrolldown(edp, n); |
433 | else |
434 | wsemul_vt100_scrollup(edp, n); |
435 | edp->scrreg_startrow = savscrstartrow; |
436 | edp->scrreg_nrows = savscrnrows; |
437 | } |
438 | break; |
439 | case 'P': /* DCH delete character */ |
440 | n = min(DEF1_ARG(edp, 0), COLS_LEFT(edp) + 1); |
441 | help = NCOLS(edp) - (edp->ccol + n); |
442 | if (help > 0) |
443 | COPYCOLS(edp, edp->ccol + n, edp->ccol, help); |
444 | ERASECOLS(edp, NCOLS(edp) - n, n, edp->bkgdattr); |
445 | break; |
446 | case 'X': /* ECH erase character */ |
447 | n = min(DEF1_ARG(edp, 0), COLS_LEFT(edp) + 1); |
448 | ERASECOLS(edp, edp->ccol, n, edp->bkgdattr); |
449 | break; |
450 | case 'c': /* DA primary */ |
451 | if (ARG(edp, 0) == 0) |
452 | wsdisplay_emulinput(edp->cbcookie, WSEMUL_VT_ID1, |
453 | sizeof(WSEMUL_VT_ID1)); |
454 | break; |
455 | case 'g': /* TBC */ |
456 | KASSERT(edp->tabs != 0); |
457 | switch (ARG(edp, 0)) { |
458 | case 0: |
459 | edp->tabs[edp->ccol] = 0; |
460 | break; |
461 | case 3: |
462 | memset(edp->tabs, 0, edp->ncols); |
463 | break; |
464 | default: |
465 | #ifdef VT100_PRINTUNKNOWN |
466 | printf("CSI%dg unknown\n" , ARG(edp, 0)); |
467 | #endif |
468 | break; |
469 | } |
470 | break; |
471 | case 'm': /* SGR select graphic rendition */ |
472 | flags = edp->attrflags; |
473 | fgcol = edp->fgcol; |
474 | bgcol = edp->bgcol; |
475 | for (n = 0; n < edp->nargs; n++) { |
476 | switch (ARG(edp, n)) { |
477 | case 0: /* reset */ |
478 | if (n == edp->nargs - 1) { |
479 | edp->bkgdattr = edp->curattr = edp->defattr; |
480 | edp->attrflags = edp->msgattrs.default_attrs; |
481 | edp->fgcol = edp->msgattrs.default_fg; |
482 | edp->bgcol = edp->msgattrs.default_bg; |
483 | return; |
484 | } |
485 | flags = edp->msgattrs.default_attrs; |
486 | fgcol = edp->msgattrs.default_fg; |
487 | bgcol = edp->msgattrs.default_bg; |
488 | break; |
489 | case 1: /* bold */ |
490 | flags |= WSATTR_HILIT; |
491 | break; |
492 | case 4: /* underline */ |
493 | flags |= WSATTR_UNDERLINE; |
494 | break; |
495 | case 5: /* blink */ |
496 | flags |= WSATTR_BLINK; |
497 | break; |
498 | case 7: /* reverse */ |
499 | flags |= WSATTR_REVERSE; |
500 | break; |
501 | case 22: /* ~bold VT300 only */ |
502 | flags &= ~WSATTR_HILIT; |
503 | break; |
504 | case 24: /* ~underline VT300 only */ |
505 | flags &= ~WSATTR_UNDERLINE; |
506 | break; |
507 | case 25: /* ~blink VT300 only */ |
508 | flags &= ~WSATTR_BLINK; |
509 | break; |
510 | case 27: /* ~reverse VT300 only */ |
511 | flags &= ~WSATTR_REVERSE; |
512 | break; |
513 | case 30: case 31: case 32: case 33: |
514 | case 34: case 35: case 36: case 37: |
515 | /* fg color */ |
516 | flags |= WSATTR_WSCOLORS; |
517 | fgcol = ARG(edp, n) - 30; |
518 | break; |
519 | case 40: case 41: case 42: case 43: |
520 | case 44: case 45: case 46: case 47: |
521 | /* bg color */ |
522 | flags |= WSATTR_WSCOLORS; |
523 | bgcol = ARG(edp, n) - 40; |
524 | break; |
525 | default: |
526 | #ifdef VT100_PRINTUNKNOWN |
527 | printf("CSI%dm unknown\n" , ARG(edp, n)); |
528 | #endif |
529 | break; |
530 | } |
531 | } |
532 | if (vt100_selectattribute(edp, flags, fgcol, bgcol, &attr, |
533 | &bkgdattr)) { |
534 | #ifdef VT100_DEBUG |
535 | printf("error allocating attr %d/%d/%x\n" , |
536 | fgcol, bgcol, flags); |
537 | #endif |
538 | } else { |
539 | edp->curattr = attr; |
540 | edp->bkgdattr = bkgdattr; |
541 | edp->attrflags = flags; |
542 | edp->fgcol = fgcol; |
543 | edp->bgcol = bgcol; |
544 | } |
545 | break; |
546 | case 'n': /* reports */ |
547 | switch (ARG(edp, 0)) { |
548 | case 5: /* DSR operating status */ |
549 | /* 0 = OK, 3 = malfunction */ |
550 | wsdisplay_emulinput(edp->cbcookie, "\033[0n" , 4); |
551 | break; |
552 | case 6: { /* DSR cursor position report */ |
553 | char buf[20]; |
554 | int row; |
555 | if (edp->flags & VTFL_DECOM) |
556 | row = ROWS_ABOVE(edp); |
557 | else |
558 | row = edp->crow; |
559 | n = snprintf(buf, sizeof(buf), "\033[%d;%dR" , |
560 | row + 1, edp->ccol + 1); |
561 | wsdisplay_emulinput(edp->cbcookie, buf, n); |
562 | } |
563 | break; |
564 | case 15: /* DSR printer status */ |
565 | /* 13 = no printer, 10 = ready, 11 = not ready */ |
566 | wsdisplay_emulinput(edp->cbcookie, "\033[?13n" , 6); |
567 | break; |
568 | case 25: /* UDK status - VT300 only */ |
569 | /* 20 = locked, 21 = unlocked */ |
570 | wsdisplay_emulinput(edp->cbcookie, "\033[?21n" , 6); |
571 | break; |
572 | case 26: /* keyboard dialect */ |
573 | /* 1 = north american , 7 = german */ |
574 | wsdisplay_emulinput(edp->cbcookie, "\033[?27;1n" , 8); |
575 | break; |
576 | default: |
577 | #ifdef VT100_PRINTUNKNOWN |
578 | printf("CSI%dn unknown\n" , ARG(edp, 0)); |
579 | #endif |
580 | break; |
581 | } |
582 | break; |
583 | case 'r': /* DECSTBM set top/bottom margins */ |
584 | help = min(DEF1_ARG(edp, 0), edp->nrows) - 1; |
585 | n = min(DEFx_ARG(edp, 1, edp->nrows), edp->nrows) - help; |
586 | if (n < 2) { |
587 | /* minimal scrolling region has 2 lines */ |
588 | return; |
589 | } else { |
590 | edp->scrreg_startrow = help; |
591 | edp->scrreg_nrows = n; |
592 | } |
593 | edp->crow = ((edp->flags & VTFL_DECOM) ? |
594 | edp->scrreg_startrow : 0); |
595 | edp->ccol = 0; |
596 | break; |
597 | case 'y': |
598 | switch (ARG(edp, 0)) { |
599 | case 4: /* DECTST invoke confidence test */ |
600 | /* ignore */ |
601 | break; |
602 | default: |
603 | #ifdef VT100_PRINTUNKNOWN |
604 | printf("CSI%dy unknown\n" , ARG(edp, 0)); |
605 | #endif |
606 | break; |
607 | } |
608 | break; |
609 | default: |
610 | #ifdef VT100_PRINTUNKNOWN |
611 | printf("CSI%c (%d, %d) unknown\n" , c, ARG(edp, 0), ARG(edp, 1)); |
612 | #endif |
613 | break; |
614 | } |
615 | } |
616 | |
617 | /* |
618 | * get an attribute from the graphics driver, |
619 | * try to find replacements if the desired appearance |
620 | * is not supported |
621 | */ |
622 | static int |
623 | vt100_selectattribute(struct vt100base_data *edp, |
624 | int flags, int fgcol, int bgcol, long *attr, long *bkgdattr) |
625 | { |
626 | int error; |
627 | |
628 | if (!(edp->scrcapabilities & WSSCREEN_WSCOLORS)) { |
629 | flags &= ~WSATTR_WSCOLORS; |
630 | #ifdef VT100_DEBUG |
631 | printf("colors ignored (impossible)\n" ); |
632 | #endif |
633 | } else |
634 | flags |= WSATTR_WSCOLORS; |
635 | error = (*edp->emulops->allocattr)(edp->emulcookie, fgcol, bgcol, |
636 | flags & WSATTR_WSCOLORS, bkgdattr); |
637 | if (error) |
638 | return (error); |
639 | |
640 | if ((flags & WSATTR_HILIT) && |
641 | !(edp->scrcapabilities & WSSCREEN_HILIT)) { |
642 | flags &= ~WSATTR_HILIT; |
643 | if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { |
644 | #if defined(WSEMUL_VT100_HILIT_FG) && WSEMUL_VT100_HILIT_FG != -1 |
645 | fgcol = WSEMUL_VT100_HILIT_FG; |
646 | #elif !defined(WSEMUL_VT100_HILIT_FG) |
647 | fgcol = WSCOL_RED; |
648 | #endif |
649 | #if defined(WSEMUL_VT100_HILIT_BG) && WSEMUL_VT100_HILIT_BG != -1 |
650 | bgcol = WSEMUL_VT100_HILIT_BG; |
651 | #endif |
652 | flags |= WSATTR_WSCOLORS; |
653 | } else { |
654 | #ifdef VT100_DEBUG |
655 | printf("bold ignored (impossible)\n" ); |
656 | #endif |
657 | } |
658 | } |
659 | if ((flags & WSATTR_UNDERLINE) && |
660 | !(edp->scrcapabilities & WSSCREEN_UNDERLINE)) { |
661 | flags &= ~WSATTR_UNDERLINE; |
662 | if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { |
663 | #if defined(WSEMUL_VT100_UNDERLINE_FG) && WSEMUL_VT100_UNDERLINE_FG != -1 |
664 | fgcol = WSEMUL_VT100_UNDERLINE_FG; |
665 | #endif |
666 | #if defined(WSEMUL_VT100_UNDERLINE_BG) && WSEMUL_VT100_UNDERLINE_BG != -1 |
667 | bgcol = WSEMUL_VT100_UNDERLINE_BG; |
668 | #elif !defined(WSEMUL_VT100_UNDERLINE_BG) |
669 | bgcol = WSCOL_BROWN; |
670 | #endif |
671 | flags |= WSATTR_WSCOLORS; |
672 | } else { |
673 | #ifdef VT100_DEBUG |
674 | printf("underline ignored (impossible)\n" ); |
675 | #endif |
676 | } |
677 | } |
678 | if ((flags & WSATTR_BLINK) && |
679 | !(edp->scrcapabilities & WSSCREEN_BLINK)) { |
680 | flags &= ~WSATTR_BLINK; |
681 | #ifdef VT100_DEBUG |
682 | printf("blink ignored (impossible)\n" ); |
683 | #endif |
684 | } |
685 | if ((flags & WSATTR_REVERSE) && |
686 | !(edp->scrcapabilities & WSSCREEN_REVERSE)) { |
687 | flags &= ~WSATTR_REVERSE; |
688 | if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { |
689 | int help; |
690 | help = bgcol; |
691 | bgcol = fgcol; |
692 | fgcol = help; |
693 | flags |= WSATTR_WSCOLORS; |
694 | } else { |
695 | #ifdef VT100_DEBUG |
696 | printf("reverse ignored (impossible)\n" ); |
697 | #endif |
698 | } |
699 | } |
700 | error = (*edp->emulops->allocattr)(edp->emulcookie, fgcol, bgcol, |
701 | flags, attr); |
702 | if (error) |
703 | return (error); |
704 | |
705 | return (0); |
706 | } |
707 | |
708 | /* |
709 | * handle device control sequences if the main state machine |
710 | * told so by setting edp->dcstype to a nonzero value |
711 | */ |
712 | void |
713 | wsemul_vt100_handle_dcs(struct vt100base_data *edp) |
714 | { |
715 | int i, pos; |
716 | |
717 | switch (edp->dcstype) { |
718 | case 0: /* not handled */ |
719 | return; |
720 | case DCSTYPE_TABRESTORE: |
721 | KASSERT(edp->tabs != 0); |
722 | memset(edp->tabs, 0, edp->ncols); |
723 | pos = 0; |
724 | for (i = 0; i < edp->dcspos; i++) { |
725 | char c = edp->dcsarg[i]; |
726 | switch (c) { |
727 | case '0': case '1': case '2': case '3': case '4': |
728 | case '5': case '6': case '7': case '8': case '9': |
729 | pos = pos * 10 + (edp->dcsarg[i] - '0'); |
730 | break; |
731 | case '/': |
732 | if (pos > 0) |
733 | edp->tabs[pos - 1] = 1; |
734 | pos = 0; |
735 | break; |
736 | default: |
737 | #ifdef VT100_PRINTUNKNOWN |
738 | printf("unknown char %c in DCS\n" , c); |
739 | #endif |
740 | break; |
741 | } |
742 | } |
743 | if (pos > 0) |
744 | edp->tabs[pos - 1] = 1; |
745 | break; |
746 | default: |
747 | panic("wsemul_vt100_handle_dcs: bad type %d" , edp->dcstype); |
748 | } |
749 | edp->dcstype = 0; |
750 | } |
751 | |
752 | static int |
753 | vt100_ansimode(struct vt100base_data *edp, int nr, int op) |
754 | { |
755 | int res = 0; /* default: unknown */ |
756 | |
757 | switch (nr) { |
758 | case 2: /* KAM keyboard locked/unlocked */ |
759 | break; |
760 | case 3: /* CRM control representation */ |
761 | break; |
762 | case 4: /* IRM insert/replace characters */ |
763 | if (op == VTMODE_SET) |
764 | edp->flags |= VTFL_INSERTMODE; |
765 | else if (op == VTMODE_RESET) |
766 | edp->flags &= ~VTFL_INSERTMODE; |
767 | res = ((edp->flags & VTFL_INSERTMODE) ? 1 : 2); |
768 | break; |
769 | case 10: /* HEM horizontal editing (permanently reset) */ |
770 | res = 4; |
771 | break; |
772 | case 12: /* SRM local echo off/on */ |
773 | res = 4; /* permanently reset ??? */ |
774 | break; |
775 | case 20: /* LNM newline = newline/linefeed */ |
776 | break; |
777 | default: |
778 | #ifdef VT100_PRINTUNKNOWN |
779 | printf("ANSI mode %d unknown\n" , nr); |
780 | #endif |
781 | break; |
782 | } |
783 | return (res); |
784 | } |
785 | |
786 | static int |
787 | vt100_decmode(struct vt100base_data *edp, int nr, int op) |
788 | { |
789 | int res = 0; /* default: unknown */ |
790 | int flags; |
791 | |
792 | flags = edp->flags; |
793 | switch (nr) { |
794 | case 1: /* DECCKM application/nomal cursor keys */ |
795 | if (op == VTMODE_SET) |
796 | flags |= VTFL_APPLCURSOR; |
797 | else if (op == VTMODE_RESET) |
798 | flags &= ~VTFL_APPLCURSOR; |
799 | res = ((flags & VTFL_APPLCURSOR) ? 1 : 2); |
800 | break; |
801 | case 2: /* DECANM ANSI vt100/vt52 */ |
802 | res = 3; /* permanently set ??? */ |
803 | break; |
804 | case 3: /* DECCOLM 132/80 cols */ |
805 | case 4: /* DECSCLM smooth/jump scroll */ |
806 | case 5: /* DECSCNM light/dark background */ |
807 | res = 4; /* all permanently reset ??? */ |
808 | break; |
809 | case 6: /* DECOM move within/outside margins */ |
810 | if (op == VTMODE_SET) |
811 | flags |= VTFL_DECOM; |
812 | else if (op == VTMODE_RESET) |
813 | flags &= ~VTFL_DECOM; |
814 | res = ((flags & VTFL_DECOM) ? 1 : 2); |
815 | break; |
816 | case 7: /* DECAWM autowrap */ |
817 | if (op == VTMODE_SET) |
818 | flags |= VTFL_DECAWM; |
819 | else if (op == VTMODE_RESET) |
820 | flags &= ~VTFL_DECAWM; |
821 | res = ((flags & VTFL_DECAWM) ? 1 : 2); |
822 | break; |
823 | case 8: /* DECARM keyboard autorepeat */ |
824 | break; |
825 | case 18: /* DECPFF print form feed */ |
826 | break; |
827 | case 19: /* DECPEX printer extent: screen/scrolling region */ |
828 | break; |
829 | case 25: /* DECTCEM text cursor on/off */ |
830 | if (op == VTMODE_SET) |
831 | flags |= VTFL_CURSORON; |
832 | else if (op == VTMODE_RESET) |
833 | flags &= ~VTFL_CURSORON; |
834 | if (flags != edp->flags) |
835 | (*edp->emulops->cursor)(edp->emulcookie, |
836 | flags & VTFL_CURSORON, |
837 | edp->crow, edp->ccol); |
838 | res = ((flags & VTFL_CURSORON) ? 1 : 2); |
839 | break; |
840 | case 42: /* DECNRCM use 7-bit NRC / |
841 | 7/8 bit from DEC multilingual or ISO-latin-1*/ |
842 | if (op == VTMODE_SET) |
843 | flags |= VTFL_NATCHARSET; |
844 | else if (op == VTMODE_RESET) |
845 | flags &= ~VTFL_NATCHARSET; |
846 | res = ((flags & VTFL_NATCHARSET) ? 1 : 2); |
847 | break; |
848 | case 66: /* DECNKM numeric keypad */ |
849 | break; |
850 | case 68: /* DECKBUM keyboard usage data processing/typewriter */ |
851 | break; |
852 | default: |
853 | #ifdef VT100_PRINTUNKNOWN |
854 | printf("DEC mode %d unknown\n" , nr); |
855 | #endif |
856 | break; |
857 | } |
858 | edp->flags = flags; |
859 | |
860 | return (res); |
861 | } |
862 | |