source: libcaca/trunk/caca/caca_conio.c @ 4369

Last change on this file since 4369 was 4369, checked in by Sam Hocevar, 12 years ago

Add the copyright unit test and update copyright information everywhere.

  • Property svn:keywords set to Id
File size: 11.4 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2010 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  This library is free software. It comes without any warranty, to
7 *  the extent permitted by applicable law. You can redistribute it
8 *  and/or modify it under the terms of the Do What The Fuck You Want
9 *  To Public License, Version 2, as published by Sam Hocevar. See
10 *  http://sam.zoy.org/wtfpl/COPYING for more details.
11 */
12
13/*
14 *  This file contains a full conio.h reimplementation. More information
15 *  on conio.h can be found on http://poli.cs.vsb.cz/c/help/conio.htm
16 */
17
18#include "config.h"
19
20#if !defined(__KERNEL__)
21#   include <stdio.h>
22#   include <stdlib.h>
23#endif
24
25#include "caca.h"
26#include "caca_internals.h"
27#include "caca_conio.h"
28
29static caca_canvas_t *cv;
30static caca_display_t *dp;
31
32static caca_timer_t refresh_timer = {0, 0};
33static uint64_t refresh_ticks;
34
35static int unget_ch = -1;
36static int kbhit_ch = -1;
37static char pass_buffer[8 + 1];
38
39static void conio_init(void);
40static void conio_refresh(void);
41static void conio_fini(void);
42
43int caca_conio_directvideo = 0;
44int caca_conio__wscroll = 1;
45
46/** \brief DOS conio.h cgets() equivalent */
47char * caca_conio_cgets(char *str)
48{
49    int len = ((uint8_t *)str)[0];
50    int pos = 0;
51
52    conio_init();
53
54    while (pos < len)
55    {
56        int ch = caca_conio_getch();
57        if (ch == '\n' || ch == '\r')
58            break;
59        str[2 + pos] = (char)(uint8_t)ch;
60        /* FIXME: handle scrolling */
61        caca_put_char(cv, caca_wherex(cv), caca_wherey(cv), ch);
62        caca_gotoxy(cv, caca_wherex(cv) + 1, caca_wherey(cv));
63        pos++;
64    }
65
66    str[2 + pos] = '\0';
67    str[1] = (char)(uint8_t)pos;
68
69    conio_refresh();
70
71    return str + 2;
72}
73
74/** \brief DOS conio.h clreol() equivalent */
75void caca_conio_clreol(void)
76{
77    conio_init();
78
79    /* FIXME: must work within the currently active text window */
80    caca_fill_box(cv, caca_wherex(cv), caca_wherey(cv),
81                  caca_get_canvas_width(cv), caca_wherey(cv), ' ');
82
83    conio_refresh();
84}
85
86/** \brief DOS conio.h clrscr() equivalent */
87void caca_conio_clrscr(void)
88{
89    conio_init();
90
91    /* FIXME: must work within the currently active text window */
92    caca_clear_canvas(cv);
93    caca_gotoxy(cv, 0, 0);
94
95    conio_refresh();
96}
97
98/** \brief DOS conio.h cprintf() equivalent */
99int caca_conio_cprintf(const char *format, ...)
100{
101    va_list args;
102    int ret;
103
104    conio_init();
105
106    /* FIXME: handle scrolling */
107    va_start(args, format);
108    ret = caca_vprintf(cv, caca_wherex(cv), caca_wherey(cv), format, args);
109    va_end(args);
110
111    caca_gotoxy(cv, caca_wherex(cv) + ret, caca_wherey(cv));
112
113    conio_refresh();
114
115    return ret;
116}
117
118/** \brief DOS conio.h cputs() equivalent */
119int caca_conio_cputs(const char *str)
120{
121    int ch;
122
123    conio_init();
124
125    while ((ch = (uint8_t)*str++))
126    {
127        /* FIXME: handle windows, scrolling, '\n' and '\r' */
128        caca_put_char(cv, caca_wherex(cv), caca_wherey(cv), ch);
129        caca_gotoxy(cv, caca_wherex(cv) + 1, caca_wherey(cv));
130    }
131
132    conio_refresh();
133
134    return ch;
135}
136
137/** \brief DOS stdio.h cscanf() equivalent */
138int caca_conio_cscanf(char *format, ...)
139{
140    conio_init();
141
142    /* TODO: implement this function */
143
144    return 0;
145}
146
147/** \brief DOS dos.h delay() equivalent */
148void caca_conio_delay(unsigned int milliseconds)
149{
150    int64_t usec = (int64_t)milliseconds * 1000;
151    caca_timer_t timer = {0, 0};
152
153    conio_init();
154
155    _caca_getticks(&timer);
156
157    /* Refresh screen as long as we have enough time */
158    while(usec > 5000)
159    {
160        conio_refresh();
161        _caca_sleep(5000);
162        usec -= _caca_getticks(&timer);
163    }
164
165    if(usec > 0)
166        _caca_sleep(usec);
167
168    conio_refresh();
169}
170
171/** \brief DOS conio.h delline() equivalent */
172void caca_conio_delline(void)
173{
174    conio_init();
175
176    /* TODO: implement this function */
177}
178
179/** \brief DOS conio.h getch() equivalent */
180int caca_conio_getch(void)
181{
182    caca_event_t ev;
183    int ret;
184
185    conio_init();
186
187    if(unget_ch >= 0)
188    {
189        int tmp = unget_ch;
190        unget_ch = -1;
191        return tmp;
192    }
193
194    if(kbhit_ch >= 0)
195    {
196        int tmp = kbhit_ch;
197        kbhit_ch = -1;
198        return tmp;
199    }
200
201    while(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, 1000) == 0)
202        conio_refresh();
203
204    ret = caca_get_event_key_ch(&ev);
205
206    conio_refresh();
207
208    return ret;
209}
210
211/** \brief DOS conio.h getche() equivalent */
212int caca_conio_getche(void)
213{
214    /* conio_init() is called here. */
215    int tmp = caca_conio_getch();
216    /* conio_refresh() is called here. */
217    caca_conio_printf("%c", tmp);
218
219    return tmp;
220}
221
222/** \brief DOS conio.h getpass() equivalent */
223char * caca_conio_getpass(const char *prompt)
224{
225    int pos = 0;
226
227    conio_init();
228
229    while (pos < 8)
230    {
231        int ch = caca_conio_getch();
232        if (ch == '\n' || ch == '\r')
233            break;
234        pass_buffer[pos] = (char)(uint8_t)ch;
235        pos++;
236    }
237
238    pass_buffer[pos] = '\0';
239
240    conio_refresh();
241
242    return pass_buffer;
243}
244
245/** \brief DOS conio.h gettext() equivalent */
246int caca_conio_gettext(int left, int top, int right, int bottom, void *destin)
247{
248    conio_init();
249
250    /* TODO: implement this function */
251
252    return 0;
253}
254
255/** \brief DOS conio.h gettextinfo() equivalent */
256void caca_conio_gettextinfo(struct caca_conio_text_info *r)
257{
258    conio_init();
259
260    /* TODO: implement this function */
261}
262
263/** \brief DOS conio.h gotoxy() equivalent */
264void caca_conio_gotoxy(int x, int y)
265{
266    conio_init();
267
268    caca_gotoxy(cv, x - 1, y - 1);
269
270    conio_refresh();
271}
272
273/** \brief DOS conio.h highvideo() equivalent */
274void caca_conio_highvideo(void)
275{
276    conio_init();
277
278    /* TODO: implement this function */
279}
280
281/** \brief DOS conio.h insline() equivalent */
282void caca_conio_insline(void)
283{
284    conio_init();
285
286    /* TODO: implement this function */
287}
288
289/** \brief DOS conio.h kbhit() equivalent */
290int caca_conio_kbhit(void)
291{
292    static caca_timer_t timer = {0, 0};
293    static int last_failed = 0;
294    caca_event_t ev;
295
296    conio_init();
297
298    /* If last call failed and this call is made less than 100µs
299     * afterwards, we assume the caller is in a busy loop and we
300     * delay it slightly to avoid resource leakage. */
301    if(last_failed && _caca_getticks(&timer) < 100)
302    {
303        _caca_sleep(1000);
304        conio_refresh();
305    }
306
307    last_failed = 0;
308
309    if(kbhit_ch >= 0)
310        return 1;
311
312    if(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, 0))
313    {
314        kbhit_ch = caca_get_event_key_ch(&ev);
315        return 1;
316    }
317
318    last_failed = 1;
319
320    return 0;
321}
322
323/** \brief DOS conio.h lowvideo() equivalent */
324void caca_conio_lowvideo(void)
325{
326    conio_init();
327
328    /* TODO: implement this function */
329}
330
331/** \brief DOS conio.h movetext() equivalent */
332int caca_conio_movetext(int left, int top, int right, int bottom,
333                        int destleft, int desttop)
334{
335    caca_canvas_t *tmp;
336
337    conio_init();
338
339    if (left < 1 || top < 1 || left > right || top > bottom
340         || destleft < 1 || desttop < 1 || destleft > right
341         || desttop > bottom || right > caca_get_canvas_width(cv)
342         || bottom > caca_get_canvas_width(cv))
343        return 0;
344
345    tmp = caca_create_canvas(right - left + 1, bottom - top + 1);
346    caca_blit(tmp, 1 - left, 1 - top, cv, NULL);
347    caca_blit(cv, destleft - 1, desttop - 1, tmp, NULL);
348
349    conio_refresh();
350
351    return 1;
352}
353
354/** \brief DOS conio.h normvideo() equivalent */
355void caca_conio_normvideo(void)
356{
357    conio_init();
358
359    /* TODO: implement this function */
360}
361
362/** \brief DOS dos.h nosound() equivalent */
363void caca_conio_nosound(void)
364{
365    conio_init();
366
367    /* TODO: implement this function */
368}
369
370/** \brief DOS stdio.h printf() equivalent */
371int caca_conio_printf(const char *format, ...)
372{
373    va_list args;
374    int ret;
375
376    conio_init();
377
378    va_start(args, format);
379    ret = caca_vprintf(cv, caca_wherex(cv), caca_wherey(cv), format, args);
380    va_end(args);
381
382    caca_gotoxy(cv, caca_wherex(cv) + ret, caca_wherey(cv));
383
384    conio_refresh();
385
386    return 0;
387}
388
389/** \brief DOS conio.h putch() equivalent */
390int caca_conio_putch(int ch)
391{
392    conio_init();
393
394    /* FIXME: handle scrolling, windows */
395    caca_put_char(cv, caca_wherex(cv), caca_wherey(cv), ch);
396    caca_gotoxy(cv, caca_wherex(cv) + 1, caca_wherey(cv));
397
398    return ch;
399}
400
401/** \brief DOS conio.h puttext() equivalent */
402int caca_conio_puttext(int left, int top, int right, int bottom, void *destin)
403{
404    conio_init();
405
406    /* TODO: implement this function */
407
408    return 0;
409}
410
411/** \brief DOS conio.h _setcursortype() equivalent */
412void caca_conio__setcursortype(int cur_t)
413{
414    conio_init();
415
416    switch(cur_t)
417    {
418        case CACA_CONIO__NOCURSOR:
419            caca_set_cursor(dp, 0);
420            break;
421        case CACA_CONIO__SOLIDCURSOR:
422        case CACA_CONIO__NORMALCURSOR:
423            caca_set_cursor(dp, 1);
424            break;
425    }
426
427    conio_refresh();
428}
429
430/** \brief DOS dos.h sleep() equivalent */
431void caca_conio_sleep(unsigned int seconds)
432{
433    int64_t usec = (int64_t)seconds * 1000000;
434    caca_timer_t timer = {0, 0};
435
436    conio_init();
437
438    _caca_getticks(&timer);
439
440    /* Refresh screen as long as we have enough time */
441    while(usec > 5000)
442    {
443        conio_refresh();
444        _caca_sleep(5000);
445        usec -= _caca_getticks(&timer);
446    }
447
448    if(usec > 0)
449        _caca_sleep(usec);
450
451    conio_refresh();
452}
453
454/** \brief DOS dos.h sound() equivalent */
455void caca_conio_sound(unsigned int frequency)
456{
457    conio_init();
458
459    /* TODO: implement this function */
460}
461
462/** \brief DOS conio.h textattr() equivalent */
463void caca_conio_textattr(int newattr)
464{
465    conio_init();
466
467    /* TODO: implement this function */
468}
469
470/** \brief DOS conio.h textbackground() equivalent */
471void caca_conio_textbackground(int newcolor)
472{
473    conio_init();
474
475    caca_set_color_ansi(cv, caca_attr_to_ansi_fg(caca_get_attr(cv, -1, -1)),
476                        newcolor);
477}
478
479/** \brief DOS conio.h textcolor() equivalent */
480void caca_conio_textcolor(int newcolor)
481{
482    conio_init();
483
484    caca_set_color_ansi(cv, newcolor,
485                        caca_attr_to_ansi_bg(caca_get_attr(cv, -1, -1)));
486}
487
488/** \brief DOS conio.h textmode() equivalent */
489void caca_conio_textmode(int newmode)
490{
491    conio_init();
492
493    /* TODO: implement this function */
494}
495
496/** \brief DOS conio.h ungetch() equivalent */
497int caca_conio_ungetch(int ch)
498{
499    conio_init();
500
501    if(unget_ch >= 0)
502        return EOF;
503
504    unget_ch = ch;
505
506    return ch;
507}
508
509/** \brief DOS conio.h wherex() equivalent */
510int caca_conio_wherex(void)
511{
512    conio_init();
513
514    return caca_wherex(cv) + 1;
515}
516
517/** \brief DOS conio.h wherey() equivalent */
518int caca_conio_wherey(void)
519{
520    conio_init();
521
522    return caca_wherey(cv) + 1;
523}
524
525/** \brief DOS conio.h window() equivalent */
526void caca_conio_window(int left, int top, int right, int bottom)
527{
528    conio_init();
529
530    /* TODO: implement this function */
531}
532
533/* XXX: the following functions are local. */
534
535static void conio_init(void)
536{
537    if(!cv)
538        cv = caca_create_canvas(80, 25);
539    if(!dp)
540    {
541        dp = caca_create_display(cv);
542        caca_refresh_display(dp);
543        caca_set_cursor(dp, 1);
544        _caca_getticks(&refresh_timer);
545        refresh_ticks = 0;
546#if defined HAVE_ATEXIT
547        atexit(conio_fini);
548#endif
549    }
550}
551
552static void conio_refresh(void)
553{
554    refresh_ticks += _caca_getticks(&refresh_timer);
555    if(refresh_ticks > 10000)
556    {
557        caca_refresh_display(dp);
558        _caca_getticks(&refresh_timer);
559        refresh_ticks = 0;
560    }
561}
562
563static void conio_fini(void)
564{
565    caca_free_display(dp);
566    dp = NULL;
567    caca_free_canvas(cv);
568    cv = NULL;
569}
570
Note: See TracBrowser for help on using the repository browser.