FreeBASIC  0.91.0
con_readline.c
Go to the documentation of this file.
1 /* comfortable INPUT function */
2 
3 #include "fb.h"
4 
5 static void DoAdjust
6  (
7  int *x, int *y,
8  int dx, int dy,
9  int cols, int rows
10  )
11 {
12  DBG_ASSERT( x!=NULL && y!=NULL );
13 
14  *x -= 1;
15  *y -= 1;
16 
17  *x += dx;
18  if( *x < 0 ) {
19  *x = -*x + cols;
20  *y -= *x / cols;
21  *x = cols - (*x % cols);
22  }
23  *y += *x / cols;
24  *x %= cols;
25  *y += dy;
26 
27  *x += 1;
28  *y += 1;
29 }
30 
31 static void DoMove
32  (
33  int *x, int *y,
34  int dx, int dy,
35  int cols, int rows
36  )
37 {
38  DoAdjust( x, y, dx, dy, cols, rows );
39  if( *y==(rows+1) && *x==1 ) {
40  fb_Locate( rows, cols, -1, 0, 0 );
41  fb_PrintBufferEx( FB_NEWLINE, sizeof(FB_NEWLINE)-1, 0 );
42  } else {
43  fb_Locate( *y, *x, -1, 0, 0 );
44  }
45 }
46 
47 FBCALL FBSTRING *fb_ConReadLine( int soft_cursor )
48 {
49  FBSTRING result = { 0 };
50 
51  int current_x, current_y;
52  int cols, rows;
53  size_t pos, len, tmp_buffer_len = 0;
54  int cursor_visible;
55  int k;
56  char tmp_buffer[12];
57 
58  fb_GetSize(&cols, &rows);
59 
60  cursor_visible = (fb_Locate( 0, 0, -1, 0, 0 ) & 0x10000) != 0;
61  fb_Locate( 0, 0, FALSE, 0, 0 );
62 
63  pos = len = 0;
64  fb_PrintBufferEx( NULL, 0, 0 );
65 
66  /* Ensure that the cursor is visible during INPUT */
67  fb_Locate( 0, 0, (soft_cursor == FALSE), 0, 0 );
68 
69  do {
70  size_t delete_char_count = 0, add_char = FALSE;
71  FBSTRING *s;
72 
73  fb_GetXY( &current_x, &current_y );
74 
75  if( soft_cursor ) {
76  fb_PrintFixString( 0, "\377", 0 );
77  fb_Locate( current_y, current_x, FALSE, 0, 0 );
78  }
79 
80  while( fb_KeyHit( ) == 0 ) {
81  fb_Delay( 25 ); /* release time slice */
82  }
83 
84  s = fb_Inkey( );
85  if( s->data ) {
86  if( FB_STRSIZE( s ) == 2 ) {
87  k = FB_MAKE_EXT_KEY( FB_CHAR_TO_INT( s->data[1] ) );
88  } else {
89  k = FB_CHAR_TO_INT( s->data[0] );
90  }
91 
92  fb_hStrDelTemp( s );
93  } else {
94  k = 0;
95  continue;
96  }
97 
98  if( soft_cursor ) {
99  char mask[2] = { ((result.data != NULL) && (pos < len)? result.data[pos]: ' '), '\0' };
100  fb_PrintFixString( 0, mask, 0 );
101  fb_Locate( current_y, current_x, FALSE, 0, 0 );
102  }
103 
104  switch( k ) {
105  case 8: /* Backspace */
106  if( pos != 0 ) {
107  DoMove( &current_x, &current_y, -1, 0, cols, rows );
108  --pos;
109  delete_char_count = 1;
110  }
111  break;
112 
113  case 9: /* TAB */
114  tmp_buffer_len = ((pos + 8) / 8 * 8) - pos;
115  memset( tmp_buffer, 32, tmp_buffer_len );
116  add_char = TRUE;
117  break;
118 
119  case 27: /* ESC */
120  DoMove( &current_x, &current_y, -pos, 0, cols, rows );
121  pos = 0;
122  delete_char_count = len;
123  break;
124 
125  case KEY_DEL: /* Delete following char */
126  /* not at EOL already? */
127  if( len != pos ) {
128  delete_char_count = 1;
129  } else {
130  fb_Beep();
131  }
132  break;
133 
134  case KEY_LEFT: /* Move cursor left */
135  /* not at begin-of-line already? */
136  if( pos != 0 ) {
137  DoMove( &current_x, &current_y, -1, 0, cols, rows );
138  --pos;
139  }
140  break;
141 
142  case KEY_RIGHT: /* Move cursor right */
143  /* not at EOL already? */
144  if( pos != len ) {
145  DoMove( &current_x, &current_y, 1, 0, cols, rows );
146  ++pos;
147  }
148  break;
149 
150  case KEY_HOME: /* Move cursor to begin-of-line */
151  DoMove( &current_x, &current_y, -pos, 0, cols, rows );
152  pos = 0;
153  break;
154 
155  case KEY_END: /* Move cursor to EOL */
156  DoMove( &current_x, &current_y, len-pos, 0, cols, rows );
157  pos = len;
158  break;
159 
160  case KEY_UP: /* Move cursor up */
161  if( pos >= cols ) {
162  DoMove( &current_x, &current_y, -cols, 0, cols, rows );
163  pos -= cols;
164  }
165  break;
166 
167  case KEY_DOWN: /* Move cursor down */
168  if( (pos + cols) <= len ) {
169  DoMove( &current_x, &current_y, cols, 0, cols, rows );
170  pos += cols;
171  }
172  break;
173 
174  default:
175  if( (k >= 32) && (k <= 255) ) {
176  tmp_buffer[0] = (char) k;
177  tmp_buffer_len = 1;
178  add_char = TRUE;
179  /* DoMove( &current_x, &current_y, 1, 0, cols ); */
180  }
181  break;
182  }
183 
184  if( (delete_char_count != 0) || add_char ) {
185  /* Turn off the cursor during output (speed-up) */
186  fb_Locate( 0, 0, FALSE, 0, 0 );
187  }
188 
189  if( delete_char_count ) {
190  FBSTRING *str_fill;
191  FBSTRING *str_left = fb_StrMid( &result, 1, pos );
192  FBSTRING *str_right = fb_StrMid( &result,
193  pos + 1 + delete_char_count,
194  len - pos - delete_char_count);
195  fb_StrAssign( &result, -1, str_left, -1, FALSE );
196  fb_StrConcatAssign( &result, -1, str_right, -1, FALSE );
197  len -= delete_char_count;
198 
199  FB_LOCK();
200 
201  fb_PrintBufferEx( result.data + pos, len - pos, 0 );
202 
203  /* Overwrite all deleted characters with SPC's */
204  str_fill = fb_StrFill1 ( delete_char_count, ' ' );
205  fb_PrintBufferEx( str_fill->data, delete_char_count, 0 );
206  fb_hStrDelTemp( str_fill );
207 
208  fb_Locate( current_y, current_x, -1, 0, 0 );
209 
210  FB_UNLOCK();
211  }
212 
213  if( add_char ) {
214  tmp_buffer[tmp_buffer_len] = 0;
215  }
216 
217  if( add_char ) {
218  int old_x = current_x, old_y = current_y;
219  FBSTRING *str_add = fb_StrAllocTempDescF( tmp_buffer, tmp_buffer_len + 1 );
220  FBSTRING *str_left = fb_StrMid( &result, 1, pos );
221  FBSTRING *str_right = fb_StrMid( &result, pos + 1, len - pos);
222  fb_StrAssign( &result, -1, str_left, -1, FALSE );
223  fb_StrConcatAssign( &result, -1, str_add, -1, FALSE );
224  fb_StrConcatAssign( &result, -1, str_right, -1, FALSE );
225  len += tmp_buffer_len;
226 
227  FB_LOCK();
228 
229  fb_PrintBufferEx( result.data + pos, len - pos, 0 );
230 
231  fb_GetXY(&current_x, &current_y);
232 
233  if( pos==(len-tmp_buffer_len) ) {
234  current_x = old_x; current_y = old_y;
235  DoMove( &current_x, &current_y, tmp_buffer_len, 0, cols, rows );
236  } else {
237  int tmp_x_2 = old_x, tmp_y_2 = old_y;
238  DoAdjust( &tmp_x_2, &tmp_y_2, len - pos, 0, cols, rows );
239  if( tmp_y_2 > (rows+1) || (tmp_y_2==(rows+1) && tmp_x_2>1) ) {
240  DoMove( &current_x, &current_y, -(len - pos - tmp_buffer_len), 0, cols, rows );
241  } else {
242  current_x = old_x; current_y = old_y;
243  DoMove( &current_x, &current_y, tmp_buffer_len, 0, cols, rows );
244  }
245  }
246  pos += tmp_buffer_len;
247 
248  FB_UNLOCK();
249  }
250 
251  fb_Locate( 0, 0, (soft_cursor == FALSE), 0, 0 );
252 
253  } while (k!='\r' && k!='\n');
254 
255  FB_LOCK();
256 
257  /* set cursor to end of line */
258  fb_GetXY(&current_x, &current_y);
259  DoMove( &current_x, &current_y, len - pos, 0, cols, rows );
260 
261  /* Restore old cursor visibility */
262  fb_Locate( 0, 0, cursor_visible, 0, 0 );
263 
264  FB_UNLOCK();
265 
266  return fb_StrAllocTempResult( &result );
267 }