FreeBASIC  0.91.0
io_printbuff_wstr.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.UnicodeChar = 32;
83 
84  ScrollConsoleScreenBufferW( 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  FillConsoleOutputCharacterW( hnd, _LC(' '), 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 FB_WCHAR *pachText = (const FB_WCHAR *) 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.UnicodeChar = pachText[i];
131  }
132 
133  result = WriteConsoleOutputW( hnd,
134  lpBuffer,
135  dwBufferSize,
136  dwBufferCoord,
137  &srWriteRegion );
138  return result;
139 }
140 
142  (
143  const FB_WCHAR *buffer,
144  size_t chars,
145  int mask
146  )
147 {
148  const FB_WCHAR *pachText = (const FB_WCHAR *) buffer;
149  int win_left, win_top, win_cols, win_rows;
150  int view_top, view_bottom;
151  fb_PrintInfo info;
152  fb_ConHooks hooks;
153 
154  /* Do we want to correct the console cursor position? */
155  if( (mask & FB_PRINT_FORCE_ADJUST)==0 )
156  {
157  /* No, we can check for the length to avoid unnecessary stuff ... */
158  if( chars == 0 )
159  return;
160  }
161 
162  FB_LOCK();
163 
164  /* is the output redirected? */
166  {
167  DWORD dwBytesWritten,
168  bytes = chars * sizeof( FB_WCHAR );
169 
170  while( bytes !=0 )
171  {
172  if( WriteFile( __fb_out_handle, pachText, bytes, &dwBytesWritten, NULL ) != TRUE )
173  break;
174 
175  pachText += dwBytesWritten;
176  bytes -= dwBytesWritten;
177  }
178 
179  FB_UNLOCK();
180  return;
181  }
182 
183  fb_ConsoleGetView( &view_top, &view_bottom );
184  fb_hConsoleGetWindow( &win_left, &win_top, &win_cols, &win_rows );
185 
186  hooks.Opaque = &info;
187  hooks.Scroll = fb_hHookConScroll;
188  hooks.Write = fb_hHookConWrite ;
189  hooks.Border.Left = win_left;
190  hooks.Border.Top = win_top + view_top - 1;
191  hooks.Border.Right = win_left + win_cols - 1;
192  hooks.Border.Bottom = win_top + view_bottom - 1;
193 
194  info.hOutput = __fb_out_handle;
195  info.rWindow.Left = win_left;
196  info.rWindow.Top = win_top;
197  info.rWindow.Right = win_left + win_cols - 1;
198  info.rWindow.Bottom = win_top + win_rows - 1;
199  info.fViewSet = hooks.Border.Top!=info.rWindow.Top
200  || hooks.Border.Bottom!=info.rWindow.Bottom;
201 
202  {
203  CONSOLE_SCREEN_BUFFER_INFO screen_info;
204 
205  if( !GetConsoleScreenBufferInfo( __fb_out_handle, &screen_info ) )
206  {
207  hooks.Coord.X = hooks.Border.Left;
208  hooks.Coord.Y = hooks.Border.Top;
211  info.wAttributes = 7;
212  }
213  else
214  {
215  hooks.Coord.X = screen_info.dwCursorPosition.X;
216  hooks.Coord.Y = screen_info.dwCursorPosition.Y;
217  info.BufferSize.X = screen_info.dwSize.X;
218  info.BufferSize.Y = screen_info.dwSize.Y;
219  info.wAttributes = screen_info.wAttributes;
220  }
221 
222  if( __fb_con.scrollWasOff )
223  {
225  ++hooks.Coord.Y;
226  hooks.Coord.X = hooks.Border.Left;
227  fb_hConCheckScroll( &hooks );
228  }
229 
230  fb_ConPrintTTYWstr( &hooks, pachText, chars, TRUE );
231 
232  if( hooks.Coord.X != hooks.Border.Left
233  || hooks.Coord.Y != (hooks.Border.Bottom+1) )
234  {
235  fb_hConCheckScroll( &hooks );
236  }
237  else
238  {
240  hooks.Coord.X = hooks.Border.Right;
241  hooks.Coord.Y = hooks.Border.Bottom;
242  }
243 
244  {
245  COORD dwCoord = { (SHORT) hooks.Coord.X, (SHORT) hooks.Coord.Y };
246  SetConsoleCursorPosition( info.hOutput,
247  dwCoord );
248  }
249  }
250 
251  if( hooks.Border.Top!=win_top && !info.fViewSet )
252  {
253  /* Now we have to ensure that the window shows the right part
254  * of the screen buffer when it was moved previously ... */
255  SMALL_RECT srWindow =
256  {
257  (SHORT) hooks.Border.Left,
258  (SHORT) hooks.Border.Top,
259  (SHORT) hooks.Border.Right,
260  (SHORT) hooks.Border.Bottom
261  };
262  SetConsoleWindowInfo( info.hOutput, TRUE, &srWindow );
263  }
264 
266 
267  FB_UNLOCK();
268 }
269 
271  (
272  const FB_WCHAR *buffer,
273  int mask
274  )
275 {
276  return fb_ConsolePrintBufferWstrEx( buffer, fb_wstr_Len( buffer ), mask );
277 }