FreeBASIC  0.91.0
io_printbuff.c
Go to the documentation of this file.
1 /* low-level print to console function */
2 
3 #include "../fb.h"
4 #include "fb_private_console.h"
5 
6 typedef struct _fb_PrintInfo {
9  WORD wAttributes;
11  int fViewSet;
12 } fb_PrintInfo;
13 
14 static void fb_hHookConScroll
15  (
17  int x1, int y1,
18  int x2, int y2,
19  int rows
20  )
21 {
22  fb_PrintInfo *pInfo = (fb_PrintInfo*) handle->Opaque;
23  HANDLE hnd = pInfo->hOutput;
24  int iBufferHeight, iScrollHeight, iClearFrom, iClearTo, iClearPos;
25 
26  SMALL_RECT srScroll;
27  COORD dwDest;
28 
29  if( !pInfo->fViewSet ) {
30  /* Try to move the window first ... */
31  if( (handle->Border.Bottom+1) < pInfo->BufferSize.Y ) {
32  int remaining = pInfo->BufferSize.Y - handle->Border.Bottom - 1;
33  int move_size = ((remaining < rows) ? remaining : rows);
34 
35  handle->Border.Top += move_size;
36  handle->Border.Bottom += move_size;
37 
38  rows -= move_size;
39  if( rows==0 )
40  return;
41  }
42 
43  /* We're at the end of the screen buffer - so we have to
44  * scroll the complete screen buffer */
45  dwDest.X = dwDest.Y = 0;
46  srScroll.Right = (SHORT) (pInfo->BufferSize.X-1);
47  srScroll.Bottom = (SHORT) (pInfo->BufferSize.Y-1);
48  iBufferHeight = pInfo->BufferSize.Y;
49 
50  } else {
51  /* Scroll only the area defined by a previous VIEW PRINT */
52  dwDest.X = (SHORT) handle->Border.Left;
53  dwDest.Y = (SHORT) handle->Border.Top;
54  srScroll.Right = (SHORT) handle->Border.Right;
55  srScroll.Bottom = (SHORT) handle->Border.Bottom;
56  iBufferHeight = handle->Border.Bottom - handle->Border.Top + 1;
57  }
58 
59  if( iBufferHeight <= rows ) {
60  /* simply clear the buffer */
61  iClearFrom = handle->Border.Top;
62  iClearTo = handle->Border.Bottom + 1;
63  } else {
64  /* Move some part of the console screen buffer to another
65  * position. */
66  CHAR_INFO FillChar;
67 
68  srScroll.Left = dwDest.X;
69  srScroll.Top = (SHORT) (dwDest.Y + rows);
70 
71  iScrollHeight = srScroll.Bottom - srScroll.Top + 1;
72  if( iScrollHeight < rows ) {
73  /* Don't forget that we have to clear some screen buffer regions
74  * not covered by the original scrolling region */
75  iClearFrom = dwDest.Y + iScrollHeight;
76  iClearTo = srScroll.Bottom + 1;
77  } else {
78  iClearFrom = iClearTo = 0;
79  }
80 
81  FillChar.Attributes = pInfo->wAttributes;
82  FillChar.Char.AsciiChar = 32;
83 
84  ScrollConsoleScreenBuffer( hnd, &srScroll, NULL, dwDest, &FillChar );
85  }
86 
87  /* Clear all parts of the screen buffer not covered by the scrolling
88  * region */
89  if( iClearFrom!=iClearTo ) {
90  SHORT x1 = handle->Border.Left;
91  WORD attr = pInfo->wAttributes;
92  DWORD width = handle->Border.Right - x1 + 1;
93  for( iClearPos=iClearFrom; iClearPos!=iClearTo; ++iClearPos ) {
94  DWORD written;
95  COORD coord = { x1, (SHORT) iClearPos };
96  FillConsoleOutputAttribute( hnd, attr, width, coord, &written);
97  FillConsoleOutputCharacter( hnd, ' ', width, coord, &written );
98  }
99  }
100 
101  handle->Coord.Y = handle->Border.Bottom;
102 }
103 
104 static int fb_hHookConWrite
105  (
106  fb_ConHooks *handle,
107  const void *buffer,
108  size_t length
109  )
110 {
111  fb_PrintInfo *pInfo = (fb_PrintInfo*) handle->Opaque;
112  HANDLE hnd = pInfo->hOutput;
113  const char *pachText = (const char *) buffer;
114  CHAR_INFO *lpBuffer = alloca( sizeof(CHAR_INFO) * length );
115  WORD wAttributes = pInfo->wAttributes;
116  COORD dwBufferSize = { (SHORT) length, 1 };
117  COORD dwBufferCoord = { 0, 0 };
118  SMALL_RECT srWriteRegion = {
119  (SHORT) handle->Coord.X,
120  (SHORT) handle->Coord.Y,
121  (SHORT) (handle->Coord.X + length - 1),
122  (SHORT) handle->Coord.Y
123  };
124  size_t i;
125  int result;
126 
127  for( i=0; i!=length; ++i ) {
128  CHAR_INFO *pCharInfo = lpBuffer + i;
129  pCharInfo->Attributes = wAttributes;
130  pCharInfo->Char.AsciiChar = pachText[i];
131  }
132  result = WriteConsoleOutput( hnd,
133  lpBuffer,
134  dwBufferSize,
135  dwBufferCoord,
136  &srWriteRegion );
137  return result;
138 }
139 
140 void fb_ConsolePrintBufferEx( const void *buffer, size_t len, int mask )
141 {
142  const char *pachText = (const char *) buffer;
143  int win_left, win_top, win_cols, win_rows;
144  int view_top, view_bottom;
145  fb_PrintInfo info;
146  fb_ConHooks hooks;
147 
148  /* Do we want to correct the console cursor position? */
149  if( (mask & FB_PRINT_FORCE_ADJUST)==0 ) {
150  /* No, we can check for the length to avoid unnecessary stuff ... */
151  if( len==0 )
152  return;
153  }
154 
155  FB_LOCK();
156 
157  if( FB_CONSOLE_WINDOW_EMPTY() ) {
158  /* output was redirected! */
159  DWORD dwBytesWritten;
160  while( len!=0 &&
161  WriteFile( __fb_out_handle,
162  pachText,
163  len,
164  &dwBytesWritten,
165  NULL ) == TRUE )
166  {
167  pachText += dwBytesWritten;
168  len -= dwBytesWritten;
169  }
170  FB_UNLOCK();
171  return;
172  }
173 
174  fb_ConsoleGetView( &view_top, &view_bottom );
175  fb_hConsoleGetWindow( &win_left, &win_top, &win_cols, &win_rows );
176 
177  hooks.Opaque = &info;
178  hooks.Scroll = fb_hHookConScroll;
179  hooks.Write = fb_hHookConWrite ;
180  hooks.Border.Left = win_left;
181  hooks.Border.Top = win_top + view_top - 1;
182  hooks.Border.Right = win_left + win_cols - 1;
183  hooks.Border.Bottom = win_top + view_bottom - 1;
184 
185  info.hOutput = __fb_out_handle;
186  info.rWindow.Left = win_left;
187  info.rWindow.Top = win_top;
188  info.rWindow.Right = win_left + win_cols - 1;
189  info.rWindow.Bottom = win_top + win_rows - 1;
190  info.fViewSet = hooks.Border.Top!=info.rWindow.Top
191  || hooks.Border.Bottom!=info.rWindow.Bottom;
192 
193  {
194  CONSOLE_SCREEN_BUFFER_INFO screen_info;
195 
196  if( !GetConsoleScreenBufferInfo( __fb_out_handle, &screen_info ) ) {
197  hooks.Coord.X = hooks.Border.Left;
198  hooks.Coord.Y = hooks.Border.Top;
201  info.wAttributes = 7;
202  } else {
203  hooks.Coord.X = screen_info.dwCursorPosition.X;
204  hooks.Coord.Y = screen_info.dwCursorPosition.Y;
205  info.BufferSize.X = screen_info.dwSize.X;
206  info.BufferSize.Y = screen_info.dwSize.Y;
207  info.wAttributes = screen_info.wAttributes;
208  }
209 
210  if( __fb_con.scrollWasOff ) {
212  ++hooks.Coord.Y;
213  hooks.Coord.X = hooks.Border.Left;
214  fb_hConCheckScroll( &hooks );
215  }
216 
217  fb_ConPrintTTY( &hooks,
218  pachText,
219  len,
220  TRUE );
221 
222  if( hooks.Coord.X != hooks.Border.Left
223  || hooks.Coord.Y != (hooks.Border.Bottom+1) )
224  {
225  fb_hConCheckScroll( &hooks );
226  }
227  else
228  {
230  hooks.Coord.X = hooks.Border.Right;
231  hooks.Coord.Y = hooks.Border.Bottom;
232  }
233 
234  {
235  COORD dwCoord = { (SHORT) hooks.Coord.X, (SHORT) hooks.Coord.Y };
236  SetConsoleCursorPosition( info.hOutput,
237  dwCoord );
238  }
239  }
240 
241  if( hooks.Border.Top!=win_top && !info.fViewSet ) {
242  /* Now we have to ensure that the window shows the right part
243  * of the screen buffer when it was moved previously ... */
244  SMALL_RECT srWindow =
245  {
246  (SHORT) hooks.Border.Left,
247  (SHORT) hooks.Border.Top,
248  (SHORT) hooks.Border.Right,
249  (SHORT) hooks.Border.Bottom
250  };
251  SetConsoleWindowInfo( info.hOutput, TRUE, &srWindow );
252  }
253 
255 
256  FB_UNLOCK();
257 }
258 
259 void fb_ConsolePrintBuffer( const char *buffer, int mask )
260 {
261  return fb_ConsolePrintBufferEx( buffer, strlen(buffer), mask );
262 }