PSX: posixw32: some work for compatibility with future SM
[reactos.git] / posix / apps / posixw32 / console.c
1 /* console.c
2 *
3 * AUTHOR: John L. Miller, johnmil@cs.cmu.edu / johnmil@jprc.com
4 * DATE: 8/4/96
5 *
6 * Copyright (c) 1996 John L. Miller
7 *
8 * Full permission is granted to use, modify and distribute
9 * this code, provided:
10 * 1) This comment field is included in its entirity
11 * 2) No money is charged for any work including or based on
12 * portions of this code.
13 *
14 * If you're a nice person and find this useful, I'd appreciate a
15 * note letting me know about it. e-mail is usually what spurs me
16 * on to improve and support software I've written.
17 *
18 * This file contains functions intended to provide the back
19 * end to a console window for my semi-vt100 emulator.
20 */
21
22 /* Note - one HUGE difference between console windows and terminal
23 * windows. Console windows displays start at (0,0). Terminal displays
24 * start at (1,1). YUCK!
25 */
26
27 #include <windows.h>
28 #include "vt100.h"
29
30 int topScrollRow=TOP_EDGE;
31 int bottomScrollRow=BOTTOM_EDGE;
32
33 /* This variable will contain terminal configuration flags, such as
34 * reverse/standard video, whether wrapping is enabled, and so on.
35 */
36 int conTermMode;
37
38 /* Variable to hold the cursor position for save/restore cursor calls */
39 COORD cursorPosSave={1,1};
40
41 /* Handles to the current console for input and output */
42 HANDLE hConIn, hConOut;
43
44 /* Array of all the tabs which are currently set. Ironically, I think the
45 * primary emulator can CLEAR tags, but not set them.
46 */
47 int tabSet[132]={0};
48 int numTabs = 0;
49
50
51 /* This section contains console-specific color information. NT consoles can
52 * have Red, blue, green, and intensity flags set. Hence, 4 con_colors.
53 */
54 #define NUM_CON_COLORS 4
55
56 /* Foreground and background colors are separated out */
57 int conForeColors, conBackColors;
58
59 /* mapping between foreground and background console colors: needed
60 * when reverse video is being used
61 */
62 int conColorMapping[NUM_CON_COLORS][2] =
63 {
64 {FOREGROUND_RED, BACKGROUND_RED},
65 {FOREGROUND_BLUE, BACKGROUND_BLUE},
66 {FOREGROUND_GREEN, BACKGROUND_GREEN},
67 {FOREGROUND_INTENSITY, BACKGROUND_INTENSITY}
68 };
69
70
71 /* Device-independant foreground and background flags stored here.
72 * probably a bad division of labor, but hey, since we don't use
73 * all of their flags in our console stuff (and hence can't retrieve
74 * them), the information has to live SOMEWHERE.
75 */
76
77 int scForeFlags, scBackFlags;
78
79 /* Defines for array indexing for translation of flags */
80 #define SC_FLAG 0
81 #define CONSOLE_FLAG 1
82
83 /* Color mapping between SC (the vt-100 emulator device independant
84 * flags) and NT console character specific flags. Flags which have no analog
85 * are set to 0. Note that all global character attributes (character set
86 * underline, bold, reverse) are all stored in foreground only
87 */
88 const int scForeMapping[NUM_SC_ATTRIBUTES][2] =
89 {
90 {SC_RED,FOREGROUND_RED},
91 {SC_GREEN,FOREGROUND_GREEN},
92 {SC_BLUE,FOREGROUND_BLUE},
93 {SC_BOLD,FOREGROUND_INTENSITY},
94 {SC_UL,0},
95 {SC_BL,0},
96 {SC_RV,0},
97 {SC_ASCII,0},
98 {SC_G0,0},
99 {SC_G1,0},
100 {SC_GRAPHICS,0}
101 };
102
103 /* Background color mapping between SC and console */
104 const int scBackMapping[NUM_SC_ATTRIBUTES][2] =
105 {
106 {SC_RED,BACKGROUND_RED},
107 {SC_GREEN,BACKGROUND_GREEN},
108 {SC_BLUE,BACKGROUND_BLUE},
109 {SC_BOLD,BACKGROUND_INTENSITY},
110 {SC_UL,0},
111 {SC_BL,0},
112 {SC_RV,0},
113 {SC_ASCII,0},
114 {SC_G0,0},
115 {SC_G1,0},
116 {SC_GRAPHICS,0}
117 };
118
119 /* These arrays map character vals 0-255 to new values.
120 * Since the G0 and G1 character sets don't have a direct analog in
121 * NT, I'm settling for replacing the ones I know what to set them
122 * to.
123 */
124 char G0Chars[256];
125 char G1Chars[256];
126
127 /* These four sets of variables are just precomputed combinations of
128 * all the possible flags to save time for masking.
129 */
130 int allFore[2], allBack[2];
131 int bothFore[2], bothBack[2];
132
133
134 /* FORWARD DECLARATIONS */
135 int
136 RawPrintLine(
137 char *text,
138 int len,
139 int scrollAtEnd
140 );
141
142 int
143 Scroll(
144 int row
145 );
146 /* END FORWARD DECLARATIONS */
147
148
149
150 /* beInitVT100Terminal() -
151 *
152 * This function is called by the VT100 emulator as soon as the
153 * front-end terminal is initialized. It's responsible for setting
154 * initial state of the terminal, and initing our many wacky variables.
155 */
156
157 int
158 beInitVT100Terminal()
159 {
160 int i;
161 CONSOLE_SCREEN_BUFFER_INFO csbi;
162
163 /* Set tabs to every 8 spaces initially */
164 numTabs = 0;
165 for (numTabs=0; numTabs < 132/8; numTabs++)
166 tabSet[numTabs] = (numTabs+1)*8;
167
168 /* Init the cursor save position to HOME */
169 cursorPosSave.X = 1;
170 cursorPosSave.Y = 1;
171
172 /* Disable scrolling window limits */
173 topScrollRow=TOP_EDGE;
174 bottomScrollRow=BOTTOM_EDGE;
175
176 conTermMode = ANSI_MODE|WRAP_MODE|REPEAT_MODE;
177
178 hConIn = GetStdHandle(STD_INPUT_HANDLE);
179 hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
180
181 /* Init our time-saving mask variables */
182 allFore[SC_FLAG] = allBack[SC_FLAG] = 0;
183 allFore[CONSOLE_FLAG] = allBack[CONSOLE_FLAG] = 0;
184 bothFore[SC_FLAG] = bothBack[SC_FLAG] = 0;
185 bothFore[CONSOLE_FLAG] = bothBack[CONSOLE_FLAG] = 0;
186
187 for (i=0; i<NUM_SC_ATTRIBUTES; i++)
188 {
189 allFore[SC_FLAG] |= scForeMapping[i][SC_FLAG];
190 allFore[CONSOLE_FLAG] |= scForeMapping[i][CONSOLE_FLAG];
191 allBack[SC_FLAG] |= scBackMapping[i][SC_FLAG];
192 allBack[CONSOLE_FLAG] |= scBackMapping[i][CONSOLE_FLAG];
193
194 if (scForeMapping[i][SC_FLAG] && scForeMapping[i][CONSOLE_FLAG])
195 {
196 bothFore[SC_FLAG] |= scForeMapping[i][SC_FLAG];
197 bothFore[CONSOLE_FLAG] |= scForeMapping[i][CONSOLE_FLAG];
198 }
199
200 if (scBackMapping[i][SC_FLAG] && scBackMapping[i][CONSOLE_FLAG])
201 {
202 bothBack[SC_FLAG] |= scBackMapping[i][SC_FLAG];
203 bothBack[CONSOLE_FLAG] |= scBackMapping[i][CONSOLE_FLAG];
204 }
205 }
206
207 conForeColors = conBackColors = 0;
208
209 for (i=0; i<NUM_CON_COLORS; i++)
210 {
211 conForeColors |= conColorMapping[i][0];
212 conBackColors |= conColorMapping[i][1];
213 }
214
215
216 /* Do initial settings for device-independant flags */
217 scForeFlags = SC_ASCII;
218 scBackFlags = 0;
219
220 GetConsoleScreenBufferInfo(hConOut, &csbi);
221
222 for (i=0; i<NUM_SC_ATTRIBUTES; i++)
223 {
224 if (csbi.wAttributes & scForeMapping[i][CONSOLE_FLAG])
225 scForeFlags |= scForeMapping[i][SC_FLAG];
226
227 if (csbi.wAttributes & scBackMapping[i][CONSOLE_FLAG])
228 scBackFlags |= scBackMapping[i][SC_FLAG];
229 }
230
231
232 /* Since the G0/G1 character sets don't really map to
233 * USASCII, So come as close as we can. By default, it'll
234 * just print the ascii character. For the graphics characters
235 * I was able to identify, change that mapping.
236 */
237
238 for (i=0; i<256; i++)
239 {
240 G0Chars[i] = i;
241 G1Chars[i] = i;
242 }
243
244 G1Chars['a']=(char)177;
245 G1Chars['f']=(char)248;
246 G1Chars['g']=(char)241;
247 G1Chars['j']=(char)217;
248 G1Chars['k']=(char)191;
249 G1Chars['l']=(char)218;
250 G1Chars['m']=(char)192;
251 G1Chars['n']=(char)197;
252 G1Chars['o']=(char)196;
253 G1Chars['p']=(char)196;
254 G1Chars['q']=(char)196;
255 G1Chars['r']=(char)196;
256 G1Chars['s']=(char)196;
257 G1Chars['t']=(char)195;
258 G1Chars['u']=(char)180;
259 G1Chars['v']=(char)193;
260 G1Chars['w']=(char)194;
261 G1Chars['x']=(char)179;
262 G1Chars['y']=(char)243;
263 G1Chars['z']=(char)242;
264
265 return(0);
266 }
267
268
269
270 /* beAbsoluteCursor -
271 *
272 * Given an input row and column, move the cursor to the
273 * absolute screen coordinates requested. Note that if the
274 * display window has scrollbars, the column is adjusted
275 * to take that into account, but the row is not. This allows
276 * for large scrollback in terminal windows.
277 *
278 * ROW must be able to accept CUR_ROW, TOP_EDGE, BOTTOM_EDGE,
279 * or a row number.
280 *
281 * COLUMN must be able to accept CUR_COL, LEFT_EDGE, RIGHT_EDGE,
282 * or a column number.
283 */
284
285 int
286 beAbsoluteCursor(
287 int row,
288 int col
289 )
290 {
291 CONSOLE_SCREEN_BUFFER_INFO csbi;
292 COORD cursorPos;
293
294 GetConsoleScreenBufferInfo(hConOut, &csbi);
295
296 if (row == CUR_ROW)
297 row = csbi.dwCursorPosition.Y;
298 else if (row == TOP_EDGE)
299 row = csbi.srWindow.Top;
300 else if (row == BOTTOM_EDGE)
301 row = csbi.srWindow.Bottom;
302 else
303 row += csbi.srWindow.Top - 1;
304
305 if (col == CUR_COL)
306 col = csbi.dwCursorPosition.X;
307 else if (col == LEFT_EDGE)
308 col = 0;
309 else if (col == RIGHT_EDGE)
310 col = csbi.dwSize.X-1;
311 else
312 col -= 1;
313
314 cursorPos.X = col;
315 cursorPos.Y = row;
316
317 SetConsoleCursorPosition(hConOut, cursorPos);
318
319 return(0);
320 }
321
322
323 /* beOffsetCursor -
324 *
325 * Given an input row and column offset, move the cursor by that
326 * many positions. For instance, row=0 and column=-1 would move
327 * the cursor left a single column.
328 *
329 * If the cursor can't move the requested amount, results are
330 * unpredictable.
331 */
332
333 int
334 beOffsetCursor(
335 int row,
336 int column
337 )
338 {
339 CONSOLE_SCREEN_BUFFER_INFO csbi;
340 COORD cursorPos;
341
342 GetConsoleScreenBufferInfo(hConOut, &csbi);
343
344 cursorPos = csbi.dwCursorPosition;
345 cursorPos.X += column;
346 cursorPos.Y += row;
347
348 if (cursorPos.X < 0)
349 cursorPos.X = 0;
350
351 if (cursorPos.X >= csbi.dwSize.X)
352 {
353 cursorPos.X -= csbi.dwSize.X;
354 cursorPos.Y += 1;
355 }
356
357 if (cursorPos.Y < 0)
358 cursorPos.Y = 0;
359
360 SetConsoleCursorPosition(hConOut, cursorPos);
361
362 return(0);
363 }
364
365
366 /* beRestoreCursor -
367 *
368 * Saved cursor position should be stored in a static
369 * variable in the back end. This function restores the
370 * cursor to the position stored in that variable.
371 */
372
373 int
374 beRestoreCursor(void)
375 {
376 CONSOLE_SCREEN_BUFFER_INFO csbi;
377 COORD cursorPos;
378
379 GetConsoleScreenBufferInfo(hConOut, &csbi);
380
381 cursorPos = csbi.dwCursorPosition;
382
383 cursorPos.Y += cursorPosSave.Y;
384
385 SetConsoleCursorPosition(hConOut, cursorPos);
386
387 return(0);
388 }
389
390 /* beSaveCursor -
391 *
392 * The back-end should maintain a static variable with the
393 * last STORED cursor position in it. This function replaces
394 * the contents of that variable with the current cursor position.
395 * The cursor may be restored to this position by using the
396 * beRestoreCursor function.
397 */
398
399 int
400 beSaveCursor(void)
401 {
402 CONSOLE_SCREEN_BUFFER_INFO csbi;
403
404 GetConsoleScreenBufferInfo(hConOut, &csbi);
405 cursorPosSave = csbi.dwCursorPosition;
406
407 cursorPosSave.Y -= csbi.srWindow.Top;
408
409 return(0);
410 }
411
412
413 /* beGetTextAttributes -
414 *
415 * given a pointer to 'fore'ground and 'back'ground ints,
416 * fill them with a device-independant description of the
417 * current foreground and background colors, as well as any
418 * font information in the foreground variable.
419 */
420
421 int
422 beGetTextAttributes(
423 int *fore,
424 int *back
425 )
426 {
427 CONSOLE_SCREEN_BUFFER_INFO csbi;
428 int i;
429
430 /* Since it's entirely possible that the text attributes were
431 * changed without our terminal being notified, we might as well
432 * make sure they're accurate.
433 */
434
435 /* First, strip out everything in the screen buffer variables
436 * that we can detect
437 */
438
439 scForeFlags &= ~bothFore[SC_FLAG];
440 scBackFlags &= ~bothBack[SC_FLAG];
441
442 /* Now, find out what the real settings are, and set the
443 * flag values accordingly.
444 */
445
446 GetConsoleScreenBufferInfo(hConOut, &csbi);
447
448
449 /* If reverse video is set, we need to reverse our color mappings
450 * before any calculations get made.
451 */
452
453 if (scForeFlags & SC_RV)
454 {
455 int tmpFore, tmpBack;
456
457 tmpFore = csbi.wAttributes & conForeColors;
458 tmpBack = csbi.wAttributes & conBackColors;
459
460 csbi.wAttributes &= ~(conForeColors | conBackColors);
461
462 for (i=0; i<NUM_CON_COLORS; i++)
463 {
464 if (tmpFore & conColorMapping[i][0])
465 csbi.wAttributes |= conColorMapping[i][1];
466
467 if (tmpBack & conColorMapping[i][1])
468 csbi.wAttributes |= conColorMapping[i][0];
469 }
470 }
471
472 /* Now, do the actual translation between our detectable
473 * console text attributes and the corresponding device-independant
474 * attributes.
475 */
476
477 for (i=0; i<NUM_SC_ATTRIBUTES; i++)
478 {
479 if (csbi.wAttributes & scForeMapping[i][CONSOLE_FLAG])
480 scForeFlags |= scForeMapping[i][SC_FLAG];
481
482 if (csbi.wAttributes & scBackMapping[i][CONSOLE_FLAG])
483 scBackFlags |= scBackMapping[i][SC_FLAG];
484 }
485
486 /* Finally, copy our updated sc flags into the variables
487 * passed in
488 */
489
490 if (fore != NULL)
491 *fore = scForeFlags;
492
493 if (back != NULL)
494 *back = scBackFlags;
495
496 return(0);
497 }
498
499
500 /* beSetTextAttributes -
501 *
502 * Given a foreground and a background device independant (SC) color and font
503 * specification, apply these to the display, and save the state in the
504 * static screen variables.
505 *
506 * Note that many font-specific constants (bold/underline/reverse, G0/G1/ASCII)
507 * are stored ONLY in the foreground specification.
508 */
509
510 int
511 beSetTextAttributes(
512 int fore,
513 int back
514 )
515 {
516 CONSOLE_SCREEN_BUFFER_INFO csbi;
517 int i;
518 WORD wAttributes;
519
520 /* First off, let's assign these settings into our
521 * device-independant holder.
522 */
523
524 scForeFlags = fore;
525 scBackFlags = back;
526
527 /* Next, determine the console's actual current settings */
528
529 GetConsoleScreenBufferInfo(hConOut, &csbi);
530
531 /* Mask out any of the attributes which can be set via
532 * our device-independant options. Since the console settings
533 * have additional options, we need to retain those so we don't
534 * do something unpleasant to our I/O abilities, for instance.
535 */
536
537 wAttributes = csbi.wAttributes;
538
539 wAttributes &= ~(bothFore[CONSOLE_FLAG] | bothBack[CONSOLE_FLAG]);
540
541 /* Now, loop through the device-independant possibilities for
542 * flags, and modify our console flags as appropriate.
543 */
544
545 for (i=0; i<NUM_SC_ATTRIBUTES; i++)
546 {
547 if (scForeFlags & scForeMapping[i][SC_FLAG])
548 wAttributes |= scForeMapping[i][CONSOLE_FLAG];
549
550 if (scBackFlags & scBackMapping[i][SC_FLAG])
551 wAttributes |= scBackMapping[i][CONSOLE_FLAG];
552 }
553
554 /* One last unpleasantry: if reverse video is set, then we should
555 * reverse the foreground and background colors
556 */
557
558 if (scForeFlags & SC_RV)
559 {
560 int tmpFore, tmpBack;
561
562 tmpFore = wAttributes & conForeColors;
563 tmpBack = wAttributes & conBackColors;
564
565 wAttributes &= ~(conForeColors | conBackColors);
566
567 for (i=0; i<NUM_CON_COLORS; i++)
568 {
569 if (tmpFore & conColorMapping[i][0])
570 wAttributes |= conColorMapping[i][1];
571
572 if (tmpBack & conColorMapping[i][1])
573 wAttributes |= conColorMapping[i][0];
574 }
575 }
576
577 /* The appropriate colors, etc. should be set in
578 * the wAttributes variable now. Apply them to the
579 * current console.
580 */
581
582 SetConsoleTextAttribute(hConOut, wAttributes);
583
584 return(0);
585 }
586
587
588 /* beRawTextOut-
589 *
590 * The name of this function is misleading. Given a pointer to
591 * ascii text and a count of bytes to print, print them to the
592 * display device. If wrapping is enabled, wrap text. If there is a
593 * scrolling region set and the cursor is in it,
594 * scroll only within that region. 'beRawTextOut' means that it's guaranteed
595 * not to have control sequences within the text.
596 */
597
598 int
599 beRawTextOut(
600 char *text,
601 int len
602 )
603 {
604 int i,j;
605
606 /* If there's no work to do, return immediately. */
607 if ((text == NULL)||(len == 0))
608 return(0);
609
610 i=0;
611
612 /* Otherwise, loop through the text until all of it has been output */
613 while (i < len)
614 {
615 /* This inner loop serves to divide the raw text to output into
616 * explicit lines. While the 'RawPrintLine' may still have to
617 * break lines to do text wrapping, explicit line breaks are
618 * handled right here.
619 */
620 j=i;
621 while ((text[j] != '\n')&&(j<len))
622 {
623 j++;
624 }
625
626 RawPrintLine(text+i, j-i, (text[j] == '\n'));
627
628 i = j+1;
629 }
630
631 return(0);
632 }
633
634
635 /* RawPrintLine -
636 *
637 * This routine is a helper for beRawTextOut. It is given a
638 * line of text which is guaranteed not to have any newlines
639 * or control characters (which need to be interpreted) in it.
640 * It prints out the text, wrapping if necessary, and handles
641 * scrolling or truncation.
642 *
643 * If scrollAtEnd is true, an extra carriage return (scroll) is
644 * performed after the text has been printed out.
645 */
646
647 int
648 RawPrintLine(
649 char *text,
650 int len,
651 int scrollAtEnd
652 )
653 {
654 int i, end;
655 CONSOLE_SCREEN_BUFFER_INFO csbi;
656 DWORD dwWritten;
657
658 if ((scrollAtEnd == FALSE) && ((text == NULL)||(len == 0)))
659 return(0);
660
661 GetConsoleScreenBufferInfo(hConOut, &csbi);
662
663 /* find out how far to the first tab or end of text */
664
665 if (text != NULL)
666 {
667 for (end=0; end<len; end++)
668 {
669 if (text[end] == '\t')
670 break;
671 }
672
673 if (end > (csbi.dwSize.X - csbi.dwCursorPosition.X))
674 end = (csbi.dwSize.X - csbi.dwCursorPosition.X);
675
676 /* If we're in non-ascii mode, we need to do a little
677 * magic to get the right characters out.
678 */
679
680 if (scForeFlags & SC_G1)
681 {
682 for (i=0; i<end; i++)
683 {
684 text[i] = G1Chars[text[i]];
685 }
686 }
687
688 /* actually print out the text. */
689
690 WriteConsole(hConOut,text,(DWORD)end,&dwWritten,NULL);
691
692 if (end == (csbi.dwSize.X - csbi.dwCursorPosition.X))
693 Scroll(CUR_ROW);
694
695 if ( (!(conTermMode & WRAP_MODE))
696 && (end == (csbi.dwSize.X - csbi.dwCursorPosition.X))
697 )
698 end = len;
699
700 if (end != len)
701 {
702 if (text[end] == '\t')
703 {
704 beAdvanceToTab();
705 RawPrintLine(text+end+1,len - (end+1), FALSE);
706 }
707 else
708 {
709 RawPrintLine(text+end, len-end, FALSE);
710 beAbsoluteCursor(CUR_ROW,1);
711 beOffsetCursor(1,0);
712 }
713 }
714 }
715
716 /* Now that we've printed this line, scroll if we need to.
717 * Note that a scroll implies a newline.
718 */
719
720 if (scrollAtEnd)
721 {
722 Scroll(CUR_ROW);
723 beAbsoluteCursor(CUR_ROW,1);
724 beOffsetCursor(1,0);
725 }
726
727 return(0);
728 }
729
730
731 /* Scroll -
732 *
733 * Given a row specification, calculate a scroll executed in that
734 * row. It could be within a scroll range, or outside of it.
735 *
736 * For some ungodly reason, I made this routine handle the TOP_EDGE,
737 * BOTTOM_EDGE, and CUR_ROW specifiers as well as a real row.
738 */
739
740 int
741 Scroll(
742 int row
743 )
744 {
745 CONSOLE_SCREEN_BUFFER_INFO csbi;
746 SMALL_RECT scrollRect;
747 COORD dest;
748 CHAR_INFO fillChar;
749
750 GetConsoleScreenBufferInfo(hConOut, &csbi);
751
752 if (row == TOP_EDGE)
753 row = csbi.srWindow.Top;
754 else if (row == BOTTOM_EDGE)
755 row = csbi.srWindow.Bottom;
756 else if (row == CUR_ROW)
757 row = csbi.dwCursorPosition.Y;
758 else
759 row += csbi.srWindow.Top;
760
761 /* Escape out if we don't really need to scroll */
762
763 if ( (row < (csbi.dwSize.Y-1))
764 && ((row-csbi.srWindow.Top + 1) < bottomScrollRow)
765 )
766 return(0);
767
768 /* NT console requires a fill character for scrolling. */
769
770 fillChar.Char.AsciiChar=' ';
771 fillChar.Attributes = csbi.wAttributes;
772
773 /* Determine the rectangle of text to scroll. Under NT this
774 * is actually an overlap-safe block-copy.
775 */
776 scrollRect.Left = 0;
777 scrollRect.Top = 1;
778 scrollRect.Right = csbi.dwSize.X;
779 scrollRect.Bottom = row;
780
781 if (topScrollRow != TOP_EDGE)
782 {
783 scrollRect.Top = csbi.srWindow.Top + topScrollRow + 1;
784 }
785
786 if ( (bottomScrollRow != BOTTOM_EDGE)
787 && ((csbi.srWindow.Top+bottomScrollRow) < scrollRect.Bottom)
788 )
789 {
790 scrollRect.Bottom = csbi.srWindow.Top + bottomScrollRow;
791 }
792
793 dest.X = 0;
794 dest.Y = scrollRect.Top - 1;
795
796 ScrollConsoleScreenBuffer(hConOut,&scrollRect,NULL,
797 dest, &fillChar);
798
799 return(0);
800 }
801
802
803 /* beEraseText -
804 *
805 * Given a 'from' and a 'to' position in display coordinates,
806 * this function will fill in all characters between the two
807 * (inclusive) with spaces. Note that the coordinates do NOT
808 * specify a rectangle. erasing from (1,1) to (2,2) erases
809 * all of the first row, and the first two characters of the
810 * second.
811 *
812 * Note that this routine must be able to handle TOP_EDGE,
813 * BOTTOM_EDGE, LEFT_EDGE, RIGHT_EDGE, CUR_ROW, and CUR_COL
814 * in the appropriate parameters.
815 */
816
817 int
818 beEraseText(
819 int rowFrom,
820 int colFrom,
821 int rowTo,
822 int colTo
823 )
824 {
825 CONSOLE_SCREEN_BUFFER_INFO csbi;
826 COORD dest, saveCursor;
827 DWORD nLength, dwWritten;
828
829 GetConsoleScreenBufferInfo(hConOut, &csbi);
830
831 saveCursor = csbi.dwCursorPosition;
832
833 /* Convert the row and column specifications into
834 * buffer coordinates
835 */
836 if (rowFrom == CUR_ROW)
837 rowFrom = csbi.dwCursorPosition.Y;
838 else if (rowFrom == TOP_EDGE)
839 rowFrom = csbi.srWindow.Top;
840 else
841 rowFrom += csbi.srWindow.Top -1;
842
843 if (colFrom == CUR_COL)
844 colFrom = csbi.dwCursorPosition.X;
845 else if (colFrom == LEFT_EDGE)
846 colFrom = 0;
847 else
848 colFrom -= 1;
849
850 if (rowTo == CUR_ROW)
851 rowTo = csbi.dwCursorPosition.Y;
852 else if (rowTo == BOTTOM_EDGE)
853 rowTo = csbi.srWindow.Bottom;
854 else
855 rowTo += csbi.srWindow.Top-1;
856
857 if (colTo == CUR_COL)
858 colTo = csbi.dwCursorPosition.X;
859 else if (colTo == RIGHT_EDGE)
860 colTo = csbi.dwSize.X;
861 else
862 colTo -= 1;
863
864 /* We're going to erase by filling a continuous range of
865 * character cells with spaces. Note that this has displeasing
866 * asthetics under NT, as highlighting appears to be immune.
867 */
868 nLength = (rowTo - rowFrom)*csbi.dwSize.X;
869 nLength += colTo - colFrom;
870
871 dest.X = colFrom;
872 dest.Y = rowFrom;
873
874 FillConsoleOutputCharacter(hConOut, ' ', nLength, dest, &dwWritten);
875 FillConsoleOutputAttribute(hConOut, csbi.wAttributes, nLength, dest, &dwWritten);
876
877 SetConsoleCursorPosition(hConOut, saveCursor);
878
879 return(0);
880 }
881
882
883 /* beDeleteText -
884 *
885 * Given a screen cursor 'from' and 'to' position, this function
886 * will delete all text between the two. Text will be scrolled
887 * up as appropriate to fill the deleted space. Note that, as in
888 * beEraseText, the two coordinates don't specify a rectangle, but
889 * rather a starting position and ending position. In other words,
890 * deleting from (1,1) to (2,2) should move the text from (2,3) to the
891 * end of the second row to (1,1), move line 3 up to line 2, and so on.
892 *
893 * This function must be able to process TOP_EDGE, BOTTOM_EDGE, LEFT_EDGE,
894 * RIGHT_EDGE, CUR_ROW, and CUR_COL specifications in the appropriate
895 * variables as well as regular row and column specifications.
896 */
897
898 int
899 beDeleteText(
900 int rowFrom,
901 int colFrom,
902 int rowTo,
903 int colTo
904 )
905 {
906 CONSOLE_SCREEN_BUFFER_INFO csbi;
907 COORD dest, saveCursor;
908 CHAR_INFO fillChar;
909
910 GetConsoleScreenBufferInfo(hConOut, &csbi);
911
912 saveCursor = csbi.dwCursorPosition;
913
914 if (rowFrom == CUR_ROW)
915 rowFrom = csbi.dwCursorPosition.Y;
916 else if (rowFrom == TOP_EDGE)
917 rowFrom = csbi.srWindow.Top;
918 else
919 rowFrom += csbi.srWindow.Top -1;
920
921 if (colFrom == CUR_COL)
922 colFrom = csbi.dwCursorPosition.X;
923 else if (colFrom == LEFT_EDGE)
924 colFrom = 0;
925 else
926 colFrom -= 1;
927
928 if (rowTo == CUR_ROW)
929 rowTo = csbi.dwCursorPosition.Y;
930 else if (rowTo == BOTTOM_EDGE)
931 rowTo = csbi.srWindow.Bottom;
932 else
933 rowTo += csbi.srWindow.Top-1;
934
935 if (colTo == CUR_COL)
936 colTo = csbi.dwCursorPosition.X;
937 else if (colTo == RIGHT_EDGE)
938 colTo = csbi.dwSize.X;
939 else
940 colTo -= 1;
941
942 fillChar.Char.AsciiChar=' ';
943 fillChar.Attributes = csbi.wAttributes;
944
945 /* Now that we've got the from and to positions
946 * set correctly, we need to delete appropriate
947 * rows and columns.
948 */
949
950 dest.X = colFrom;
951 dest.Y = rowFrom;
952
953 /* BUGBUG - need to implement this. What can I say, I'm lazy :) */
954
955 return(0);
956 }
957
958
959 /* beInsertRow -
960 *
961 * Given a row number or CUR_ROW, TOP_EDGE or BOTTOM_EDGE as an input,
962 * this function will scroll all text from the current row down down by one,
963 * and create a blank row under the cursor.
964 */
965
966 int
967 beInsertRow(
968 int row
969 )
970 {
971 CONSOLE_SCREEN_BUFFER_INFO csbi;
972 COORD dest;
973 CHAR_INFO fillChar;
974 SMALL_RECT scrollRect;
975
976 GetConsoleScreenBufferInfo(hConOut, &csbi);
977
978 fillChar.Char.AsciiChar=' ';
979 fillChar.Attributes = csbi.wAttributes;
980
981 if (row == CUR_ROW)
982 row = csbi.dwCursorPosition.Y;
983 else if (row == TOP_EDGE)
984 row = csbi.srWindow.Top;
985 else if (row == BOTTOM_EDGE)
986 row = csbi.srWindow.Bottom;
987 else
988 row += csbi.srWindow.Top-1;
989
990 dest.X = 0;
991 dest.Y = row+1;
992
993 scrollRect.Top = row;
994 scrollRect.Left = 0;
995 scrollRect.Right = csbi.dwSize.X;
996 scrollRect.Bottom = csbi.srWindow.Bottom;
997
998 ScrollConsoleScreenBuffer(hConOut, &scrollRect, NULL, dest, &fillChar);
999
1000 return(0);
1001 }
1002
1003
1004 /* beTransmitText -
1005 *
1006 * Given a pointer to text and byte count, this routine should transmit data
1007 * to whatever host made the request it's responding to. Typically this routin
1008 * should transmit data as though the user had typed it in.
1009 */
1010
1011 int
1012 beTransmitText(
1013 char *text,
1014 int len
1015 )
1016 {
1017 if ((text == NULL) || (len < 1))
1018 return(0);
1019
1020 /* BUGBUG - need to implement this. */
1021
1022 return(0);
1023 }
1024
1025
1026 /* beAdvanceToTab -
1027 *
1028 * This routine will destructively advance the cursor to the
1029 * next set tab, or to the end of the line if there are no
1030 * more tabs to the right of the cursor.
1031 */
1032
1033 int
1034 beAdvanceToTab(void)
1035 {
1036 CONSOLE_SCREEN_BUFFER_INFO csbi;
1037 int i, col, tocol;
1038 COORD dest;
1039 DWORD dwWritten;
1040
1041 GetConsoleScreenBufferInfo(hConOut,&csbi);
1042
1043 col = csbi.dwCursorPosition.X+1;
1044
1045 dest = csbi.dwCursorPosition;
1046
1047 for(i=0; i<numTabs; i++)
1048 {
1049 if (col < tabSet[i])
1050 {
1051 tocol = tabSet[i];
1052 break;
1053 }
1054 }
1055
1056 if (i == numTabs)
1057 {
1058 tocol = csbi.dwSize.X;
1059 }
1060
1061 FillConsoleOutputCharacter(hConOut, ' ', tocol-col,
1062 dest, &dwWritten);
1063
1064 beOffsetCursor(0,tocol-col);
1065
1066 return(0);
1067 }
1068
1069
1070 /* beClearTab -
1071 *
1072 * This function accepts a constant, and will try to clear tabs
1073 * appropriately. Its argument is either
1074 * ALL_TABS, meaning all tabs should be removed
1075 * CUR_COL, meaning the tab in the current column should be wiped, or
1076 * a column value, meaning if there's a tab there it should be wiped.
1077 *
1078 */
1079
1080 int
1081 beClearTab(
1082 int col
1083 )
1084 {
1085 int i, j;
1086 CONSOLE_SCREEN_BUFFER_INFO csbi;
1087
1088 if (col == ALL_TABS)
1089 {
1090 tabSet[0] = 0;
1091 numTabs = 0;
1092 return(0);
1093 }
1094
1095 if (col == CUR_COL)
1096 {
1097 GetConsoleScreenBufferInfo(hConOut,&csbi);
1098 col = csbi.dwCursorPosition.X+1;
1099 }
1100
1101 for (i=0; i<numTabs; i++)
1102 {
1103 if (tabSet[i] == col)
1104 {
1105 numTabs -= 1;
1106
1107 for (j=i; j<numTabs; j++)
1108 tabSet[j]=tabSet[j+1];
1109
1110 break;
1111 }
1112 }
1113
1114 return(0);
1115 }
1116
1117 /* beSetScrollingRows -
1118 *
1119 * Given a pair of row numbers, this routine will set the scrolling
1120 * rows to those values. Note that this routine will accept
1121 * TOP_ROW and BOTTOM_ROW as values, meaning that scrolling should
1122 * be enabled for the entire display, regardless of resizing.
1123 */
1124
1125 int
1126 beSetScrollingRows(
1127 int fromRow,
1128 int toRow
1129 )
1130 {
1131 if (fromRow > toRow)
1132 return(-1);
1133
1134 topScrollRow = fromRow;
1135 bottomScrollRow = toRow;
1136
1137 return(0);
1138 }
1139
1140
1141 /* beRingBell -
1142 *
1143 * Ring the system bell once.
1144 */
1145
1146 int
1147 beRingBell(void)
1148 {
1149 MessageBeep((UINT)-1);
1150 return(0);
1151 }
1152
1153
1154 /* beGetTermMode -
1155 *
1156 * Return the value of conTermMode, which is the terminal settings which
1157 * can be queried/set by <esc>[?#h/l.
1158 */
1159
1160 int
1161 beGetTermMode()
1162 {
1163 return(conTermMode);
1164 }
1165
1166
1167 /* beSetTermMode -
1168 *
1169 * Set the terminal as requested, assuming we can. Right now we only handle a
1170 * couple of the possible flags, but we store many of the others.
1171 */
1172
1173 int beSetTermMode(
1174 int newMode
1175 )
1176 {
1177 int i, changes;
1178 CONSOLE_SCREEN_BUFFER_INFO csbi;
1179 COORD newSize;
1180 SMALL_RECT newWindowRect;
1181 DWORD dwConMode;
1182
1183 changes = conTermMode ^ newMode;
1184
1185 /* For each bit set in 'changes', determine the
1186 * appropriate course of action.
1187 */
1188
1189 for (i=0; i < NUM_TERM_ATTR_MODES; i++)
1190 {
1191 if (termAttrMode[i] & changes)
1192 {
1193 switch(termAttrMode[i])
1194 {
1195 case COL132_MODE:
1196 GetConsoleScreenBufferInfo(hConOut, &csbi);
1197 newSize.Y = csbi.dwSize.Y;
1198 newSize.X = (newMode & COL132_MODE) ? 132 : 80;
1199 if (newSize.X != csbi.dwSize.X)
1200 {
1201 newWindowRect.Top = csbi.srWindow.Top;
1202 newWindowRect.Bottom = csbi.srWindow.Bottom;
1203 newWindowRect.Left = 0;
1204 newWindowRect.Right = csbi.dwSize.X - 1;
1205 SetConsoleScreenBufferSize(hConOut, newSize);
1206 SetConsoleWindowInfo(hConOut, TRUE, &newWindowRect);
1207 }
1208 break;
1209
1210 case WRAP_MODE:
1211 GetConsoleMode(hConOut,&dwConMode);
1212 if ( (newMode & WRAP_MODE)
1213 && (! (dwConMode & ENABLE_WRAP_AT_EOL_OUTPUT))
1214 )
1215 {
1216 dwConMode |= ENABLE_WRAP_AT_EOL_OUTPUT;
1217 SetConsoleMode(hConOut, dwConMode);
1218 }
1219 if ( (!(newMode & WRAP_MODE))
1220 && (dwConMode & ENABLE_WRAP_AT_EOL_OUTPUT)
1221 )
1222 {
1223 dwConMode &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
1224 SetConsoleMode(hConOut, dwConMode);
1225 }
1226 break;
1227
1228 case CURSORAPPL_MODE:
1229 case ANSI_MODE:
1230 case SMOOTHSCROLL_MODE:
1231 case REVSCREEN_MODE:
1232 case ORIGINREL_MODE:
1233 case REPEAT_MODE:
1234 /* bugbug - we don't handle any of these. */
1235 break;
1236 }
1237 }
1238 }
1239
1240 conTermMode = newMode;
1241
1242 return(0);
1243 }