25 |
#include <iconv.h> |
#include <iconv.h> |
26 |
#include <argp.h> |
#include <argp.h> |
27 |
#include <string.h> |
#include <string.h> |
28 |
|
#include <assert.h> |
29 |
|
#include <error.h> |
30 |
|
|
31 |
#include <sys/io.h> |
#include <sys/io.h> |
|
#include <sys/mman.h> |
|
32 |
#include <sys/fcntl.h> |
#include <sys/fcntl.h> |
33 |
|
#include <sys/mman.h> |
34 |
#include <cthreads.h> |
#include <cthreads.h> |
35 |
|
|
36 |
|
#include <hurd.h> |
37 |
|
#include <hurd/pager.h> |
38 |
|
|
39 |
#ifndef __STDC_ISO_10646__ |
#ifndef __STDC_ISO_10646__ |
40 |
#error It is required that wchar_t is UCS-4. |
#error It is required that wchar_t is UCS-4. |
41 |
#endif |
#endif |
42 |
|
|
43 |
|
#include "console.h" |
44 |
#include "display.h" |
#include "display.h" |
45 |
|
|
46 |
|
|
|
struct screen |
|
|
{ |
|
|
/* A screen matrix, including the scroll back buffer. */ |
|
|
wchar_t *matrix; |
|
|
|
|
|
/* The size of the screen, in lines. */ |
|
|
int lines; |
|
|
|
|
|
/* The top most line of the screen in the video buffer. */ |
|
|
int current_line; |
|
|
|
|
|
/* Maximum number of lines scrolled back. */ |
|
|
int scrolling_max; |
|
|
|
|
|
int width; |
|
|
int height; |
|
|
}; |
|
|
typedef struct screen *screen_t; |
|
|
|
|
47 |
struct cursor |
struct cursor |
48 |
{ |
{ |
|
/* The visibility of the cursor. */ |
|
|
u_int32_t status; |
|
|
#define CURSOR_INVISIBLE 1 |
|
|
#define CURSOR_STANDOUT 2 |
|
|
|
|
|
u_int32_t x; |
|
|
u_int32_t y; |
|
49 |
u_int32_t saved_x; |
u_int32_t saved_x; |
50 |
u_int32_t saved_y; |
u_int32_t saved_y; |
51 |
}; |
}; |
108 |
}; |
}; |
109 |
typedef struct attr *attr_t; |
typedef struct attr *attr_t; |
110 |
|
|
111 |
|
struct user_pager_info |
112 |
|
{ |
113 |
|
display_t display; |
114 |
|
struct pager *p; |
115 |
|
}; |
116 |
|
|
117 |
struct display |
struct display |
118 |
{ |
{ |
119 |
/* The lock for the virtual console display structure. */ |
/* The lock for the virtual console display structure. */ |
120 |
struct mutex lock; |
struct mutex lock; |
121 |
|
|
|
struct screen screen; |
|
|
struct cursor cursor; |
|
|
struct output output; |
|
|
struct attr attr; |
|
|
|
|
122 |
/* Indicates if OWNER_ID is initialized. */ |
/* Indicates if OWNER_ID is initialized. */ |
123 |
int has_owner; |
int has_owner; |
124 |
/* Specifies the ID of the process that should receive the WINCH |
/* Specifies the ID of the process that should receive the WINCH |
125 |
signal for this virtual console. */ |
signal for this virtual console. */ |
126 |
int owner_id; |
int owner_id; |
127 |
|
|
128 |
|
struct cursor cursor; |
129 |
|
struct output output; |
130 |
|
struct attr attr; |
131 |
|
struct cons_display *user; |
132 |
|
|
133 |
|
struct user_pager_info *upi; |
134 |
|
memory_object_t memobj; |
135 |
|
size_t memobj_size; |
136 |
}; |
}; |
137 |
|
|
138 |
|
|
139 |
|
/* We need a separate bucket for the pager ports. */ |
140 |
|
struct port_bucket *pager_bucket; |
141 |
|
|
142 |
|
mach_port_t |
143 |
|
display_get_filemap (display_t display, vm_prot_t prot) |
144 |
|
{ |
145 |
|
error_t err; |
146 |
|
|
147 |
|
/* Add a reference for each call, the caller will deallocate it. */ |
148 |
|
err = mach_port_mod_refs (mach_task_self (), display->memobj, |
149 |
|
MACH_PORT_RIGHT_SEND, +1); |
150 |
|
assert_perror (err); |
151 |
|
|
152 |
|
return display->memobj; |
153 |
|
} |
154 |
|
|
155 |
|
/* Implement the pager_clear_user_data callback from the pager library. */ |
156 |
|
void |
157 |
|
pager_clear_user_data (struct user_pager_info *upi) |
158 |
|
{ |
159 |
|
free (upi); |
160 |
|
} |
161 |
|
|
162 |
|
/* XXX This is not good enough. We actually need to provide a backing |
163 |
|
store. */ |
164 |
|
error_t |
165 |
|
pager_read_page (struct user_pager_info *pager, vm_offset_t page, |
166 |
|
vm_address_t *buf, int *writelock) |
167 |
|
{ |
168 |
|
/* This is a read-only medium */ |
169 |
|
*writelock = 1; |
170 |
|
|
171 |
|
*buf = (vm_address_t) mmap (0, vm_page_size, PROT_READ|PROT_WRITE, |
172 |
|
MAP_ANON, 0, 0); |
173 |
|
return 0; |
174 |
|
} |
175 |
|
|
176 |
|
error_t |
177 |
|
pager_write_page (struct user_pager_info *pager, |
178 |
|
vm_offset_t page, |
179 |
|
vm_address_t buf) |
180 |
|
{ |
181 |
|
/* XXX Implement me. */ |
182 |
|
assert (0); |
183 |
|
} |
184 |
|
|
185 |
|
error_t |
186 |
|
pager_unlock_page (struct user_pager_info *pager, |
187 |
|
vm_offset_t address) |
188 |
|
{ |
189 |
|
return 0; |
190 |
|
} |
191 |
|
|
192 |
|
/* Tell how big the file is. */ |
193 |
|
error_t |
194 |
|
pager_report_extent (struct user_pager_info *upi, |
195 |
|
vm_address_t *offset, |
196 |
|
vm_size_t *size) |
197 |
|
{ |
198 |
|
display_t display = upi->display; |
199 |
|
*offset = 0; |
200 |
|
*size = display->memobj_size; |
201 |
|
return 0; |
202 |
|
} |
203 |
|
|
204 |
|
void |
205 |
|
pager_dropweak (struct user_pager_info *upi) |
206 |
|
{ |
207 |
|
} |
208 |
|
|
209 |
|
/* A top-level function for the paging thread that just services paging |
210 |
|
requests. */ |
211 |
|
static void |
212 |
|
service_paging_requests (any_t arg) |
213 |
|
{ |
214 |
|
struct port_bucket *pager_bucket = arg; |
215 |
|
for (;;) |
216 |
|
ports_manage_port_operations_multithread (pager_bucket, |
217 |
|
pager_demuxer, |
218 |
|
1000 * 60 * 2, |
219 |
|
1000 * 60 * 10, 0); |
220 |
|
} |
221 |
|
|
222 |
|
|
223 |
static error_t |
static error_t |
224 |
screen_init (screen_t screen) |
user_create (display_t display, u_int32_t width, u_int32_t height, |
225 |
|
u_int32_t lines) |
226 |
{ |
{ |
227 |
screen->width = 80; |
error_t err; |
228 |
screen->height = 25; |
struct cons_display *user; |
229 |
screen->lines = 25; /* XXX For now. */ |
display->memobj_size = round_page (sizeof (struct cons_display) + |
230 |
screen->current_line = 0; |
sizeof (u_int32_t) * width * lines); |
231 |
screen->matrix = calloc (screen->lines * screen->width, sizeof (wchar_t)); |
|
232 |
if (!screen->matrix) |
display->upi = malloc (sizeof (struct user_pager_info)); |
233 |
return ENOMEM; |
if (!display->upi) |
234 |
|
return MACH_PORT_NULL; |
235 |
|
display->upi->display = display; |
236 |
|
/* 1 & MOCD correct? */ |
237 |
|
display->upi->p = pager_create (display->upi, pager_bucket, |
238 |
|
1, MEMORY_OBJECT_COPY_DELAY); |
239 |
|
if (display->upi->p == 0) |
240 |
|
{ |
241 |
|
free (display->upi); |
242 |
|
return errno; |
243 |
|
} |
244 |
|
display->memobj = pager_get_port (display->upi->p); |
245 |
|
ports_port_deref (display->upi->p); |
246 |
|
|
247 |
|
mach_port_insert_right (mach_task_self (), display->memobj, display->memobj, |
248 |
|
MACH_MSG_TYPE_MAKE_SEND); |
249 |
|
|
250 |
|
err = vm_map (mach_task_self (), |
251 |
|
(vm_address_t *) &user, (vm_size_t) display->memobj_size, |
252 |
|
(vm_address_t) 0, |
253 |
|
1 /* ! (flags & MAP_FIXED) */, |
254 |
|
display->memobj, 0 /* (vm_offset_t) offset */, |
255 |
|
0 /* ! (flags & MAP_SHARED) */, |
256 |
|
VM_PROT_READ | VM_PROT_WRITE, |
257 |
|
VM_PROT_READ | VM_PROT_WRITE, |
258 |
|
VM_INHERIT_NONE); |
259 |
|
if (err) |
260 |
|
{ |
261 |
|
/* UPI will be cleaned up by libpager. */ |
262 |
|
mach_port_deallocate (mach_task_self (), display->memobj); |
263 |
|
return err; |
264 |
|
} |
265 |
|
|
266 |
|
user->magic = CONS_MAGIC; |
267 |
|
user->version = CONS_VERSION_MAJ << 16 | CONS_VERSION_AGE; |
268 |
|
user->screen.width = width; |
269 |
|
user->screen.height = height; |
270 |
|
user->screen.lines = lines; |
271 |
|
user->screen.cur_line = 0; |
272 |
|
user->screen.scr_lines = 0; |
273 |
|
user->screen.matrix = sizeof (struct cons_display) / sizeof (u_int32_t); |
274 |
|
user->cursor.col = 0; |
275 |
|
user->cursor.row = 0; |
276 |
|
user->cursor.status = CONS_CURSOR_NORMAL; |
277 |
|
wmemset (user->_matrix, L' ', user->screen.width * user->screen.lines); |
278 |
|
|
|
wmemset (screen->matrix, L' ', screen->height * screen->width); |
|
279 |
/* XXX Set attribute flags. */ |
/* XXX Set attribute flags. */ |
280 |
|
display->user = user; |
281 |
return 0; |
return 0; |
282 |
} |
} |
283 |
|
|
284 |
static void |
static void |
285 |
screen_deinit (screen_t screen) |
user_destroy (display_t display) |
286 |
{ |
{ |
287 |
free (screen->matrix); |
/* The pager will be deallocated by libpager. */ |
288 |
|
mach_port_deallocate (mach_task_self (), display->memobj); |
289 |
} |
} |
290 |
|
|
291 |
|
|
292 |
|
#define MATRIX_POS(user,x,y) ((user)->_matrix \ |
293 |
|
+ (((user)->screen.cur_line + (y)) % (user)->screen.height) \ |
294 |
|
* (user)->screen.width + (x)) |
295 |
|
|
296 |
static void |
static void |
297 |
screen_fill (screen_t screen, size_t x, size_t y, size_t w, size_t h, |
screen_fill (display_t display, size_t x, size_t y, size_t w, size_t h, |
298 |
wchar_t chr, char attr) |
wchar_t chr, char attr) |
299 |
{ |
{ |
300 |
wchar_t *matrixp = screen->matrix |
struct cons_display *user = display->user; |
301 |
+ ((screen->current_line + y) % screen->height) * screen->width + x; |
wchar_t *matrixp = MATRIX_POS (user, x, y); |
302 |
|
|
303 |
while (h--) |
while (h--) |
304 |
{ |
{ |
305 |
/* XXX Set attribute flags. */ |
/* XXX Set attribute flags. */ |
306 |
wmemset (matrixp, L' ', w); |
wmemset (matrixp, L' ', w); |
307 |
matrixp += screen->width; |
matrixp += user->screen.width; |
308 |
} |
} |
309 |
|
|
310 |
/* XXX Flag screen change, but here? */ |
/* XXX Flag screen change, but here or where else? */ |
311 |
} |
} |
312 |
|
|
313 |
static void |
static void |
314 |
screen_scroll_up (screen_t screen, size_t x, size_t y, size_t w, size_t h, |
screen_scroll_up (display_t display, size_t x, size_t y, size_t w, size_t h, |
315 |
int amt, wchar_t chr, char attr) |
int amt, wchar_t chr, char attr) |
316 |
{ |
{ |
317 |
wchar_t *matrixp = screen->matrix |
struct cons_display *user = display->user; |
318 |
+ ((screen->current_line + y) % screen->height) * screen->width + x; |
wchar_t *matrixp = MATRIX_POS (user, x, y); |
319 |
|
|
320 |
if (amt < 0) |
if (amt < 0) |
321 |
return; |
return; |
322 |
|
|
323 |
while (h-- > amt) |
while (h-- > amt) |
324 |
{ |
{ |
325 |
wmemcpy (matrixp, matrixp + amt * screen->width, w); |
wmemcpy (matrixp, matrixp + amt * user->screen.width, w); |
326 |
matrixp += screen->width; |
matrixp += user->screen.width; |
327 |
} |
} |
328 |
screen_fill (screen, x, y, w, h, chr, attr); |
screen_fill (display, x, y, w, h, chr, attr); |
329 |
} |
} |
330 |
|
|
331 |
static void |
static void |
332 |
screen_scroll_down (screen_t screen, size_t x, size_t y, size_t w, size_t h, |
screen_scroll_down (display_t display, size_t x, size_t y, size_t w, size_t h, |
333 |
int amt, wchar_t chr, char attr) |
int amt, wchar_t chr, char attr) |
334 |
{ |
{ |
335 |
wchar_t *matrixp = screen->matrix |
struct cons_display *user = display->user; |
336 |
+ ((screen->current_line + y + h - 1) % screen->height) |
wchar_t *matrixp = MATRIX_POS (user, x, y + h - 1); |
|
* screen->width + x; |
|
337 |
|
|
338 |
if (amt < 0) |
if (amt < 0) |
339 |
return; |
return; |
340 |
|
|
341 |
while (h-- > amt) |
while (h-- > amt) |
342 |
{ |
{ |
343 |
wmemcpy (matrixp, matrixp - amt * screen->width, w); |
wmemcpy (matrixp, matrixp - amt * user->screen.width, w); |
344 |
matrixp -= screen->width; |
matrixp -= user->screen.width; |
345 |
} |
} |
346 |
screen_fill (screen, x, y, w, h, chr, attr); |
screen_fill (display, x, y, w, h, chr, attr); |
347 |
} |
} |
348 |
|
|
349 |
static void |
static void |
350 |
screen_scroll_left (screen_t screen, size_t x, size_t y, size_t w, size_t h, |
screen_scroll_left (display_t display, size_t x, size_t y, size_t w, size_t h, |
351 |
int amt, wchar_t chr, char attr) |
int amt, wchar_t chr, char attr) |
352 |
{ |
{ |
353 |
|
struct cons_display *user = display->user; |
354 |
|
wchar_t *matrixp = MATRIX_POS (user, x, y); |
355 |
int i; |
int i; |
|
wchar_t *matrixp = screen->matrix |
|
|
+ ((screen->current_line + y) % screen->height) * screen->width + x; |
|
356 |
|
|
357 |
if (amt < 0) |
if (amt < 0) |
358 |
return; |
return; |
362 |
for (i = 0; i < y + h; i++) |
for (i = 0; i < y + h; i++) |
363 |
{ |
{ |
364 |
wmemmove (matrixp, matrixp + amt, w - amt); |
wmemmove (matrixp, matrixp + amt, w - amt); |
365 |
matrixp += screen->width; |
matrixp += user->screen.width; |
366 |
} |
} |
367 |
screen_fill (screen, x + w - amt, y, amt, h, chr, attr); |
screen_fill (display, x + w - amt, y, amt, h, chr, attr); |
368 |
} |
} |
369 |
|
|
370 |
static void |
static void |
371 |
screen_scroll_right (screen_t screen, size_t x, size_t y, size_t w, size_t h, |
screen_scroll_right (display_t display, size_t x, size_t y, size_t w, size_t h, |
372 |
int amt, wchar_t chr, char attr) |
int amt, wchar_t chr, char attr) |
373 |
{ |
{ |
374 |
|
struct cons_display *user = display->user; |
375 |
|
wchar_t *matrixp = MATRIX_POS (user, x, y); |
376 |
int i; |
int i; |
|
wchar_t *matrixp = screen->matrix |
|
|
+ ((screen->current_line + y) % screen->height) * screen->width + x; |
|
377 |
|
|
378 |
if (amt < 0) |
if (amt < 0) |
379 |
return; |
return; |
383 |
for (i = 0; i < y + h; i++) |
for (i = 0; i < y + h; i++) |
384 |
{ |
{ |
385 |
wmemmove (matrixp + amt, matrixp, w - amt); |
wmemmove (matrixp + amt, matrixp, w - amt); |
386 |
matrixp += screen->width; |
matrixp += user->screen.width; |
387 |
} |
} |
388 |
screen_fill (screen, x, y, amt, h, chr, attr); |
screen_fill (display, x, y, amt, h, chr, attr); |
389 |
} |
} |
390 |
|
|
391 |
|
|
413 |
|
|
414 |
|
|
415 |
static void |
static void |
416 |
handle_esc_bracket_hl (cursor_t cursor, int code, int flag) |
handle_esc_bracket_hl (display_t display, int code, int flag) |
417 |
{ |
{ |
418 |
switch (code) |
switch (code) |
419 |
{ |
{ |
420 |
case 34: |
case 34: |
421 |
/* Cursor standout: <cnorm>, <cvvis>. */ |
/* Cursor standout: <cnorm>, <cvvis>. */ |
422 |
if (flag) |
if (flag) |
423 |
cursor->status |= CURSOR_STANDOUT; |
display->user->cursor.status = CONS_CURSOR_VERY_VISIBLE; |
424 |
else |
else |
425 |
cursor->status &= ~CURSOR_STANDOUT; |
display->user->cursor.status = CONS_CURSOR_NORMAL; |
426 |
/* XXX Flag cursor status change. */ |
/* XXX Flag cursor status change. */ |
427 |
break; |
break; |
428 |
} |
} |
514 |
static void |
static void |
515 |
handle_esc_bracket (display_t display, char op) |
handle_esc_bracket (display_t display, char op) |
516 |
{ |
{ |
517 |
|
struct cons_display *user = display->user; |
518 |
parse_t parse = &display->output.parse; |
parse_t parse = &display->output.parse; |
519 |
int i; |
int i; |
520 |
|
|
521 |
static void limit_cursor (void) |
static void limit_cursor (void) |
522 |
{ |
{ |
523 |
if (display->cursor.x >= display->screen.width) |
if (user->cursor.col >= user->screen.width) |
524 |
display->cursor.x = display->screen.width - 1; |
user->cursor.col = user->screen.width - 1; |
525 |
else if (display->cursor.x < 0) |
else if (user->cursor.col < 0) |
526 |
display->cursor.x = 0; |
user->cursor.col = 0; |
527 |
|
|
528 |
if (display->cursor.y >= display->screen.height) |
if (user->cursor.row >= user->screen.height) |
529 |
display->cursor.y = display->screen.height - 1; |
user->cursor.row = user->screen.height - 1; |
530 |
else if (display->cursor.y < 0) |
else if (user->cursor.row < 0) |
531 |
display->cursor.y = 0; |
user->cursor.row = 0; |
532 |
|
|
533 |
/* XXX Flag cursor change. */ |
/* XXX Flag cursor change. */ |
534 |
} |
} |
538 |
case 'H': |
case 'H': |
539 |
case 'f': |
case 'f': |
540 |
/* Cursor position: <cup>. */ |
/* Cursor position: <cup>. */ |
541 |
display->cursor.x = parse->params[1] - 1; |
user->cursor.col = parse->params[1] - 1; |
542 |
display->cursor.y = parse->params[0] - 1; |
user->cursor.row = parse->params[0] - 1; |
543 |
limit_cursor (); |
limit_cursor (); |
544 |
break; |
break; |
545 |
case 'G': |
case 'G': |
546 |
/* Horizontal position: <hpa>. */ |
/* Horizontal position: <hpa>. */ |
547 |
display->cursor.x = parse->params[0] - 1; |
user->cursor.col = parse->params[0] - 1; |
548 |
limit_cursor (); |
limit_cursor (); |
549 |
break; |
break; |
550 |
case 'F': |
case 'F': |
551 |
/* Beginning of previous line. */ |
/* Beginning of previous line. */ |
552 |
display->cursor.x = 0; |
user->cursor.col = 0; |
553 |
/* fall through */ |
/* fall through */ |
554 |
case 'A': |
case 'A': |
555 |
/* Cursor up: <cuu>, <cuu1>. */ |
/* Cursor up: <cuu>, <cuu1>. */ |
556 |
display->cursor.y -= (parse->params[0] ?: 1); |
user->cursor.row -= (parse->params[0] ?: 1); |
557 |
limit_cursor (); |
limit_cursor (); |
558 |
break; |
break; |
559 |
case 'E': |
case 'E': |
560 |
/* Beginning of next line. */ |
/* Beginning of next line. */ |
561 |
display->cursor.x = 0; |
user->cursor.col = 0; |
562 |
/* Fall through. */ |
/* Fall through. */ |
563 |
case 'B': |
case 'B': |
564 |
/* Cursor down: <cud1>, <cud>. */ |
/* Cursor down: <cud1>, <cud>. */ |
565 |
display->cursor.y += (parse->params[0] ?: 1); |
user->cursor.row += (parse->params[0] ?: 1); |
566 |
limit_cursor (); |
limit_cursor (); |
567 |
break; |
break; |
568 |
case 'C': |
case 'C': |
569 |
/* Cursor right: <cuf1>, <cuf>. */ |
/* Cursor right: <cuf1>, <cuf>. */ |
570 |
display->cursor.x += (parse->params[0] ?: 1); |
user->cursor.col += (parse->params[0] ?: 1); |
571 |
limit_cursor (); |
limit_cursor (); |
572 |
break; |
break; |
573 |
case 'D': |
case 'D': |
574 |
/* Cursor left: <cub>, <cub1>. */ |
/* Cursor left: <cub>, <cub1>. */ |
575 |
display->cursor.x -= (parse->params[0] ?: 1); |
user->cursor.col -= (parse->params[0] ?: 1); |
576 |
limit_cursor (); |
limit_cursor (); |
577 |
break; |
break; |
578 |
case 's': |
case 's': |
579 |
/* Save cursor position: <sc>. */ |
/* Save cursor position: <sc>. */ |
580 |
display->cursor.saved_x = display->cursor.x; |
display->cursor.saved_x = user->cursor.col; |
581 |
display->cursor.saved_y = display->cursor.y; |
display->cursor.saved_y = user->cursor.row; |
582 |
break; |
break; |
583 |
case 'u': |
case 'u': |
584 |
/* Restore cursor position: <rc>. */ |
/* Restore cursor position: <rc>. */ |
585 |
display->cursor.x = display->cursor.saved_x; |
user->cursor.col = display->cursor.saved_x; |
586 |
display->cursor.y = display->cursor.saved_y; |
user->cursor.row = display->cursor.saved_y; |
587 |
/* In case the screen was larger before: */ |
/* In case the screen was larger before: */ |
588 |
limit_cursor (); |
limit_cursor (); |
589 |
break; |
break; |
590 |
case 'h': |
case 'h': |
591 |
/* Reset mode. */ |
/* Reset mode. */ |
592 |
for (i = 0; i < parse->nparams; i++) |
for (i = 0; i < parse->nparams; i++) |
593 |
handle_esc_bracket_hl (&display->cursor, parse->params[i], 0); |
handle_esc_bracket_hl (display, parse->params[i], 0); |
594 |
break; |
break; |
595 |
case 'l': |
case 'l': |
596 |
/* Set mode. */ |
/* Set mode. */ |
597 |
for (i = 0; i < parse->nparams; i++) |
for (i = 0; i < parse->nparams; i++) |
598 |
handle_esc_bracket_hl (&display->cursor, parse->params[i], 1); |
handle_esc_bracket_hl (display, parse->params[i], 1); |
599 |
break; |
break; |
600 |
case 'm': |
case 'm': |
601 |
for (i = 0; i < parse->nparams; i++) |
for (i = 0; i < parse->nparams; i++) |
606 |
{ |
{ |
607 |
case 0: |
case 0: |
608 |
/* Clear to end of screen: <ed>. */ |
/* Clear to end of screen: <ed>. */ |
609 |
screen_fill (&display->screen, display->cursor.x, display->cursor.y, |
screen_fill (display, user->cursor.col, user->cursor.row, |
610 |
display->screen.width - display->cursor.x, 1, L' ', |
user->screen.width - user->cursor.col, 1, L' ', |
611 |
display->attr.current); |
display->attr.current); |
612 |
screen_fill (&display->screen, 0, display->cursor.y + 1, |
screen_fill (display, 0, user->cursor.row + 1, |
613 |
display->screen.width, |
user->screen.width, |
614 |
display->screen.height - display->cursor.y, |
user->screen.height - user->cursor.row, |
615 |
L' ', display->attr.current); |
L' ', display->attr.current); |
616 |
break; |
break; |
617 |
case 1: |
case 1: |
618 |
/* Clear to beginning of screen. */ |
/* Clear to beginning of screen. */ |
619 |
screen_fill (&display->screen, 0, 0, |
screen_fill (display, 0, 0, |
620 |
display->screen.width, display->cursor.y, |
user->screen.width, user->cursor.row, |
621 |
L' ', display->attr.current); |
L' ', display->attr.current); |
622 |
screen_fill (&display->screen, 0, display->cursor.y, |
screen_fill (display, 0, user->cursor.row, |
623 |
display->cursor.x + 1, 1, |
user->cursor.col + 1, 1, |
624 |
L' ', display->attr.current); |
L' ', display->attr.current); |
625 |
break; |
break; |
626 |
case 2: |
case 2: |
627 |
/* Clear entire screen. */ |
/* Clear entire screen. */ |
628 |
screen_fill (&display->screen, 0, 0, |
screen_fill (display, 0, 0, |
629 |
display->screen.width, display->screen.height, |
user->screen.width, user->screen.height, |
630 |
L' ', display->attr.current); |
L' ', display->attr.current); |
631 |
break; |
break; |
632 |
} |
} |
636 |
{ |
{ |
637 |
case 0: |
case 0: |
638 |
/* Clear to end of line: <el>. */ |
/* Clear to end of line: <el>. */ |
639 |
screen_fill (&display->screen, display->cursor.x, display->cursor.y, |
screen_fill (display, user->cursor.col, user->cursor.row, |
640 |
display->screen.width - display->cursor.x, 1, |
user->screen.width - user->cursor.col, 1, |
641 |
L' ', display->attr.current); |
L' ', display->attr.current); |
642 |
break; |
break; |
643 |
case 1: |
case 1: |
644 |
/* Clear to beginning of line: <el1>. */ |
/* Clear to beginning of line: <el1>. */ |
645 |
screen_fill (&display->screen, 0, display->cursor.y, |
screen_fill (display, 0, user->cursor.row, |
646 |
display->cursor.x + 1, 1, |
user->cursor.col + 1, 1, |
647 |
L' ', display->attr.current); |
L' ', display->attr.current); |
648 |
break; |
break; |
649 |
case 2: |
case 2: |
650 |
/* Clear entire line. */ |
/* Clear entire line. */ |
651 |
screen_fill (&display->screen, 0, display->cursor.y, |
screen_fill (display, 0, user->cursor.row, |
652 |
display->screen.width, 1, |
user->screen.width, 1, |
653 |
L' ', display->attr.current); |
L' ', display->attr.current); |
654 |
break; |
break; |
655 |
} |
} |
656 |
break; |
break; |
657 |
case 'L': |
case 'L': |
658 |
/* Insert line(s): <il1>, <il>. */ |
/* Insert line(s): <il1>, <il>. */ |
659 |
screen_scroll_down (&display->screen, 0, display->cursor.y, |
screen_scroll_down (display, 0, user->cursor.row, |
660 |
display->screen.width, |
user->screen.width, |
661 |
display->screen.height - display->cursor.y, |
user->screen.height - user->cursor.row, |
662 |
parse->params[0] ?: 1, |
parse->params[0] ?: 1, |
663 |
L' ', display->attr.current); |
L' ', display->attr.current); |
664 |
break; |
break; |
665 |
case 'M': |
case 'M': |
666 |
/* Delete line(s): <dl1>, <dl>. */ |
/* Delete line(s): <dl1>, <dl>. */ |
667 |
screen_scroll_up (&display->screen, 0, display->cursor.y, |
screen_scroll_up (display, 0, user->cursor.row, |
668 |
display->screen.width, |
user->screen.width, |
669 |
display->screen.height - display->cursor.y, |
user->screen.height - user->cursor.row, |
670 |
parse->params[0] ?: 1, |
parse->params[0] ?: 1, |
671 |
L' ', display->attr.current); |
L' ', display->attr.current); |
672 |
break; |
break; |
673 |
case '@': |
case '@': |
674 |
/* Insert character(s): <ich1>, <ich>. */ |
/* Insert character(s): <ich1>, <ich>. */ |
675 |
screen_scroll_right (&display->screen, display->cursor.x, |
screen_scroll_right (display, user->cursor.col, |
676 |
display->cursor.y, |
user->cursor.row, |
677 |
display->screen.width - display->cursor.x, 1, |
user->screen.width - user->cursor.col, 1, |
678 |
parse->params[0] ?: 1, |
parse->params[0] ?: 1, |
679 |
L' ', display->attr.current); |
L' ', display->attr.current); |
680 |
break; |
break; |
681 |
case 'P': |
case 'P': |
682 |
/* Delete character(s): <dch1>, <dch>. */ |
/* Delete character(s): <dch1>, <dch>. */ |
683 |
screen_scroll_left (&display->screen, display->cursor.x, |
screen_scroll_left (display, user->cursor.col, |
684 |
display->cursor.y, |
user->cursor.row, |
685 |
display->screen.width - display->cursor.x, 1, |
user->screen.width - user->cursor.col, 1, |
686 |
parse->params[0] ?: 1, |
parse->params[0] ?: 1, |
687 |
L' ', display->attr.current); |
L' ', display->attr.current); |
688 |
break; |
break; |
689 |
case 'S': |
case 'S': |
690 |
/* Scroll up: <ind>, <indn>. */ |
/* Scroll up: <ind>, <indn>. */ |
691 |
screen_scroll_up (&display->screen, 0, 0, |
screen_scroll_up (display, 0, 0, |
692 |
display->screen.width, display->screen.height, |
user->screen.width, user->screen.height, |
693 |
parse->params[0] ?: 1, |
parse->params[0] ?: 1, |
694 |
L' ', display->attr.current); |
L' ', display->attr.current); |
695 |
break; |
break; |
696 |
case 'T': |
case 'T': |
697 |
/* Scroll down: <ri>, <rin>. */ |
/* Scroll down: <ri>, <rin>. */ |
698 |
screen_scroll_down (&display->screen, 0, 0, |
screen_scroll_down (display, 0, 0, |
699 |
display->screen.width, display->screen.height, |
user->screen.width, user->screen.height, |
700 |
parse->params[0] ?: 1, |
parse->params[0] ?: 1, |
701 |
L' ', display->attr.current); |
L' ', display->attr.current); |
702 |
break; |
break; |
703 |
case 'X': |
case 'X': |
704 |
/* Erase character(s): <ech>. */ |
/* Erase character(s): <ech>. */ |
705 |
screen_fill (&display->screen, display->cursor.x, display->cursor.y, |
screen_fill (display, user->cursor.col, user->cursor.row, |
706 |
parse->params[0] ?: 1, 1, |
parse->params[0] ?: 1, 1, |
707 |
L' ', display->attr.current); |
L' ', display->attr.current); |
708 |
break; |
break; |
717 |
case 25: |
case 25: |
718 |
/* Cursor invisibility: <civis>, <cnorm>. */ |
/* Cursor invisibility: <civis>, <cnorm>. */ |
719 |
if (flag) |
if (flag) |
720 |
display->cursor.status |= CURSOR_INVISIBLE; |
display->user->cursor.status = CONS_CURSOR_INVISIBLE; |
721 |
else |
else |
722 |
display->cursor.status &= ~CURSOR_INVISIBLE; |
display->user->cursor.status = CONS_CURSOR_NORMAL; |
723 |
/* XXX Flag cursor status change. */ |
/* XXX Flag cursor status change. */ |
724 |
break; |
break; |
725 |
} |
} |
751 |
static void |
static void |
752 |
display_output_one (display_t display, wchar_t chr) |
display_output_one (display_t display, wchar_t chr) |
753 |
{ |
{ |
754 |
|
struct cons_display *user = display->user; |
755 |
parse_t parse = &display->output.parse; |
parse_t parse = &display->output.parse; |
756 |
|
|
757 |
void newline (void) |
void newline (void) |
758 |
{ |
{ |
759 |
if (display->cursor.y < display->screen.height - 1) |
if (user->cursor.row < user->screen.height - 1) |
760 |
{ |
{ |
761 |
display->cursor.y++; |
user->cursor.row++; |
762 |
/* XXX Flag cursor update. */ |
/* XXX Flag cursor update. */ |
763 |
} |
} |
764 |
else |
else |
765 |
{ |
{ |
766 |
display->screen.current_line++; |
user->screen.cur_line++; |
767 |
display->screen.current_line %= display->screen.lines; |
user->screen.cur_line %= user->screen.lines; |
768 |
|
|
769 |
/* XXX Set attribute flags. */ |
/* XXX Set attribute flags. */ |
770 |
screen_fill (&display->screen, 0, display->screen.height - 1, |
screen_fill (display, 0, user->screen.height - 1, |
771 |
display->screen.width, 1, L' ', display->screen.width); |
user->screen.width, 1, L' ', user->screen.width); |
772 |
if (display->screen.scrolling_max < |
if (user->screen.scr_lines < |
773 |
display->screen.lines - display->screen.height) |
user->screen.lines - user->screen.height) |
774 |
display->screen.scrolling_max++; |
user->screen.scr_lines++; |
775 |
/* XXX Flag current line change. */ |
/* XXX Flag current line change. */ |
776 |
/* XXX Flag change of last line. */ |
/* XXX Flag change of last line. */ |
777 |
/* XXX Possibly flag change of length of scroll back buffer. */ |
/* XXX Possibly flag change of length of scroll back buffer. */ |
785 |
{ |
{ |
786 |
case L'\r': |
case L'\r': |
787 |
/* Carriage return: <cr>. */ |
/* Carriage return: <cr>. */ |
788 |
if (display->cursor.x) |
if (user->cursor.col) |
789 |
{ |
{ |
790 |
display->cursor.x = 0; |
user->cursor.col = 0; |
791 |
/* XXX Flag cursor update. */ |
/* XXX Flag cursor update. */ |
792 |
} |
} |
793 |
break; |
break; |
797 |
break; |
break; |
798 |
case L'\b': |
case L'\b': |
799 |
/* Cursor backward: <cub1>. */ |
/* Cursor backward: <cub1>. */ |
800 |
if (display->cursor.x > 0 || display->cursor.y > 0) |
if (user->cursor.col > 0 || user->cursor.row > 0) |
801 |
{ |
{ |
802 |
if (display->cursor.x > 0) |
if (user->cursor.col > 0) |
803 |
display->cursor.x--; |
user->cursor.col--; |
804 |
else |
else |
805 |
{ |
{ |
806 |
/* XXX This implements the <bw> functionality. |
/* XXX This implements the <bw> functionality. |
807 |
The alternative is to cut off and set x to 0. */ |
The alternative is to cut off and set x to 0. */ |
808 |
display->cursor.x = display->screen.width - 1; |
user->cursor.col = user->screen.width - 1; |
809 |
display->cursor.y--; |
user->cursor.row--; |
810 |
} |
} |
811 |
/* XXX Flag cursor update. */ |
/* XXX Flag cursor update. */ |
812 |
} |
} |
813 |
break; |
break; |
814 |
case L'\t': |
case L'\t': |
815 |
/* Horizontal tab: <ht> */ |
/* Horizontal tab: <ht> */ |
816 |
display->cursor.x = (display->cursor.x | 7) + 1; |
user->cursor.col = (user->cursor.col | 7) + 1; |
817 |
if (display->cursor.x >= display->screen.width) |
if (user->cursor.col >= user->screen.width) |
818 |
{ |
{ |
819 |
display->cursor.x = 0; |
user->cursor.col = 0; |
820 |
newline (); |
newline (); |
821 |
} |
} |
822 |
/* XXX Flag cursor update. */ |
/* XXX Flag cursor update. */ |
829 |
break; |
break; |
830 |
default: |
default: |
831 |
{ |
{ |
832 |
int line = (display->screen.current_line + display->cursor.y) |
int line = (user->screen.cur_line + user->cursor.row) |
833 |
% display->screen.lines; |
% user->screen.lines; |
834 |
|
|
835 |
/* XXX Set attribute flags. */ |
/* XXX Set attribute flags. */ |
836 |
display->screen.matrix[line * display->screen.width |
user->_matrix[line * user->screen.width |
837 |
+ display->cursor.x] = chr; |
+ user->cursor.col] = chr; |
838 |
|
|
839 |
display->cursor.x++; |
user->cursor.col++; |
840 |
if (display->cursor.x == display->screen.width) |
if (user->cursor.col == user->screen.width) |
841 |
{ |
{ |
842 |
display->cursor.x = 0; |
user->cursor.col = 0; |
843 |
newline (); |
newline (); |
844 |
} |
} |
845 |
} |
} |
855 |
break; |
break; |
856 |
case L'c': |
case L'c': |
857 |
/* Clear screen and home cursor: <clear>. */ |
/* Clear screen and home cursor: <clear>. */ |
858 |
screen_fill (&display->screen, 0, 0, |
screen_fill (display, 0, 0, |
859 |
display->screen.width, display->screen.height, |
user->screen.width, user->screen.height, |
860 |
L' ', display->attr.current); |
L' ', display->attr.current); |
861 |
display->cursor.x = display->cursor.y = 0; |
user->cursor.col = user->cursor.row = 0; |
862 |
/* XXX Flag cursor change. */ |
/* XXX Flag cursor change. */ |
863 |
parse->state = STATE_NORMAL; |
parse->state = STATE_NORMAL; |
864 |
break; |
break; |
944 |
return err; |
return err; |
945 |
} |
} |
946 |
|
|
947 |
|
void |
948 |
|
display_init (void) |
949 |
|
{ |
950 |
|
/* Create the pager bucket, and start to serve paging requests. */ |
951 |
|
pager_bucket = ports_create_bucket (); |
952 |
|
if (! pager_bucket) |
953 |
|
error (5, errno, "Cannot create pager bucket"); |
954 |
|
|
955 |
|
/* Make a thread to service paging requests. */ |
956 |
|
cthread_detach (cthread_fork ((cthread_fn_t) service_paging_requests, |
957 |
|
(any_t)pager_bucket)); |
958 |
|
} |
959 |
|
|
960 |
/* Create a new virtual console display, with the system encoding |
/* Create a new virtual console display, with the system encoding |
961 |
being ENCODING. */ |
being ENCODING. */ |
962 |
error_t |
error_t |
964 |
{ |
{ |
965 |
error_t err = 0; |
error_t err = 0; |
966 |
display_t display; |
display_t display; |
967 |
|
int width = 80; |
968 |
|
int height = 25; |
969 |
|
int lines = 25; /* XXX For now. */ |
970 |
|
|
971 |
*r_display = NULL; |
*r_display = NULL; |
972 |
display = calloc (1, sizeof *display); |
display = calloc (1, sizeof *display); |
974 |
return ENOMEM; |
return ENOMEM; |
975 |
|
|
976 |
mutex_init (&display->lock); |
mutex_init (&display->lock); |
977 |
err = screen_init (&display->screen); |
err = user_create (display, width, height, lines); |
978 |
if (err) |
if (err) |
979 |
{ |
{ |
980 |
free (display); |
free (display); |
984 |
err = output_init (&display->output, encoding); |
err = output_init (&display->output, encoding); |
985 |
if (err) |
if (err) |
986 |
{ |
{ |
987 |
screen_deinit (&display->screen); |
user_destroy (display); |
988 |
free (display); |
free (display); |
989 |
} |
} |
990 |
*r_display = display; |
*r_display = display; |
997 |
display_destroy (display_t display) |
display_destroy (display_t display) |
998 |
{ |
{ |
999 |
output_deinit (&display->output); |
output_deinit (&display->output); |
1000 |
screen_deinit (&display->screen); |
user_destroy (display); |
1001 |
free (display); |
free (display); |
1002 |
} |
} |
1003 |
|
|
1007 |
display_getsize (display_t display, struct winsize *winsize) |
display_getsize (display_t display, struct winsize *winsize) |
1008 |
{ |
{ |
1009 |
mutex_lock (&display->lock); |
mutex_lock (&display->lock); |
1010 |
winsize->ws_row = display->screen.height; |
winsize->ws_row = display->user->screen.height; |
1011 |
winsize->ws_col = display->screen.width; |
winsize->ws_col = display->user->screen.width; |
1012 |
winsize->ws_xpixel = 0; |
winsize->ws_xpixel = 0; |
1013 |
winsize->ws_ypixel = 0; |
winsize->ws_ypixel = 0; |
1014 |
mutex_unlock (&display->lock); |
mutex_unlock (&display->lock); |
1145 |
return amount; |
return amount; |
1146 |
} |
} |
1147 |
|
|
1148 |
ssize_t display_read (display_t display, int nonblock, off_t off, |
ssize_t |
1149 |
char *data, size_t len) |
display_read (display_t display, int nonblock, off_t off, |
1150 |
|
char *data, size_t len) |
1151 |
{ |
{ |
|
u_int32_t metadata[8]; |
|
|
size_t metadatalen = sizeof (metadata); |
|
|
ssize_t written = 0; |
|
|
|
|
1152 |
mutex_lock (&display->lock); |
mutex_lock (&display->lock); |
1153 |
metadata[0] = display->screen.width; |
memcpy (data, ((char *) display->user) + off, len); |
|
metadata[1] = display->screen.height; |
|
|
metadata[2] = display->screen.lines; |
|
|
metadata[3] = display->screen.current_line; |
|
|
metadata[4] = display->screen.scrolling_max; |
|
|
metadata[5] = display->cursor.x; |
|
|
metadata[6] = display->cursor.y; |
|
|
metadata[7] = display->cursor.status; |
|
|
|
|
|
if (off >= 0 && off < metadatalen) |
|
|
{ |
|
|
int part_len = len; |
|
|
|
|
|
if (part_len > metadatalen) |
|
|
part_len = metadatalen; |
|
|
memcpy (data, (char *) metadata + off, part_len); |
|
|
data += part_len; |
|
|
len -= part_len; |
|
|
written += part_len; |
|
|
} |
|
|
off -= metadatalen; |
|
|
if (off < 0) |
|
|
off = 0; |
|
|
|
|
|
if (off + len > 2000 * sizeof(wchar_t)) |
|
|
len = 2000 * sizeof(wchar_t) - off; |
|
|
memcpy (data, (char *) display->screen.matrix + off, len); |
|
1154 |
mutex_unlock (&display->lock); |
mutex_unlock (&display->lock); |
1155 |
return written + len; |
return len; |
1156 |
} |
} |
1157 |
|
|
1158 |
/* Resume the output on the display DISPLAY. */ |
/* Resume the output on the display DISPLAY. */ |