123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- /*
- term.c - terminal functions
- Copyright (c) 1999 - 2006 NoisyB
- Copyright (c) 2001 - 2005, 2015 dbjh
- Copyright (c) 2002 - 2004 Jan-Erik Karlsson (Amiga code)
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- // gcc term.c -o term -ltermcap -DUSE_TERMCAP
- // st_term_t and term_*() functions taken and modified from LAME frontend/console.c
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #ifdef USE_TERMCAP
- #include <termcap.h>
- #endif
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #ifdef _WIN32
- #ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable: 4255) // 'function' : no function prototype given: converting '()' to '(void)'
- #pragma warning(disable: 4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
- #pragma warning(disable: 4820) // 'bytes' bytes padding added after construct 'member_name'
- #endif
- #include <io.h> // isatty() (MinGW)
- #include <windows.h> // HANDLE, SetConsoleTextAttribute()
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif
- #endif // _WIN32
- #ifdef DJGPP
- #include <dpmi.h> // needed for __dpmi_int() by ansi_init()
- #endif
- #include "misc/term.h"
- #include "ucon64_defines.h"
- #ifdef __CYGWIN__ // on Cygwin (gcc for Windows) we
- #define USE_POLL // need poll() for kbhit(). poll()
- #include <sys/poll.h> // is available on Linux, not on
- #endif // BeOS. DOS already has kbhit()
- #if (defined __unix__ && !defined __MSDOS__) || defined __BEOS__ || \
- defined __APPLE__ // Mac OS X actually
- #include <termios.h>
- typedef struct termios tty_t;
- #endif
- typedef struct
- {
- #if defined _WIN32 && !defined __CYGWIN__
- HANDLE Console_Handle;
- #endif
- int w; // display width
- int h; // display height
- char up[10];
- char clreoln[10];
- char emph[10];
- char norm[10];
- } st_term_t;
- static st_term_t term;
- int
- term_open (void)
- {
- st_term_t *t = &term;
- #ifdef USE_TERMCAP
- char *tp;
- char tc[10];
- int val;
- #endif
- // defaults
- memset (t, 0, sizeof (st_term_t));
- t->w = 80;
- t->h = 25;
- #if defined _WIN32 && !defined __CYGWIN__
- t->Console_Handle = GetStdHandle (STD_ERROR_HANDLE);
- #endif
- strcpy (t->up, "\033[A");
- #ifdef USE_TERMCAP
- // try to catch additional information about special termsole sequences
- #if 0
- if (!(term_name = getenv ("TERM")))
- return -1;
- if (tgetent (term_buff, term_name) != 1)
- return -1;
- #endif
- val = tgetnum ("co");
- if (val >= 40 && val <= 512)
- t->w = val;
- val = tgetnum ("li");
- if (val >= 16 && val <= 256)
- t->h = val;
- *(tp = tc) = 0;
- tp = tgetstr ("up", &tp);
- if (tp)
- strcpy (t->up, tp);
- *(tp = tc) = 0;
- tp = tgetstr ("ce", &tp);
- if (tp)
- strcpy (t->clreoln, tp);
- *(tp = tc) = 0;
- tp = tgetstr ("md", &tp);
- if (tp)
- strcpy (t->emph, tp);
- *(tp = tc) = 0;
- tp = tgetstr ("me", &tp);
- if (tp)
- strcpy (t->norm, tp);
- #endif // USE_TERMCAP
- return 0;
- }
- int
- term_close (void)
- {
- st_term_t *t = &term;
- if (t)
- {
- memset (t, 0, sizeof (st_term_t));
- // free (t);
- }
- return 0;
- }
- int
- term_w (void)
- {
- st_term_t *t = &term;
- return t->w;
- }
- int
- term_h (void)
- {
- st_term_t *t = &term;
- return t->h;
- }
- const char *
- term_up (void)
- {
- st_term_t *t = &term;
- return t->up;
- }
- const char *
- term_clreoln (void)
- {
- st_term_t *t = &term;
- return t->clreoln;
- }
- const char *
- term_emph (void)
- {
- st_term_t *t = &term;
- return t->emph;
- }
- const char *
- term_norm (void)
- {
- st_term_t *t = &term;
- return t->norm;
- }
- static int misc_ansi_color = 0;
- #if (defined __unix__ && !defined __MSDOS__) || defined __BEOS__ || \
- defined __APPLE__ // Mac OS X actually
- static void set_tty (tty_t *param);
- #endif
- #if defined _WIN32 && defined USE_ANSI_COLOR
- int
- vprintf2 (const char *format, va_list argptr)
- // Cheap hack to get the Visual C++ and MinGW ports support "ANSI colors".
- // Cheap, because it only supports the ANSI escape sequences uCON64 uses.
- {
- #undef printf
- #undef fprintf
- int n_chars = 0, n_ctrl = 0, n_print, done = 0;
- char output[MAXBUFSIZE], *ptr, *ptr2;
- HANDLE stdout_handle;
- CONSOLE_SCREEN_BUFFER_INFO info;
- WORD org_attr, new_attr = 0;
- n_chars = _vsnprintf (output, MAXBUFSIZE, format, argptr);
- if (n_chars == -1)
- {
- fprintf (stderr, "INTERNAL ERROR: Output buffer in vprintf2() is too small (%d bytes).\n"
- " Please send a bug report\n", MAXBUFSIZE);
- exit (1);
- }
- output[MAXBUFSIZE - 1] = 0;
- if ((ptr = strchr (output, 0x1b)) == NULL)
- fputs (output, stdout);
- else
- {
- stdout_handle = GetStdHandle (STD_OUTPUT_HANDLE);
- GetConsoleScreenBufferInfo (stdout_handle, &info);
- org_attr = info.wAttributes;
- if (ptr > output)
- {
- *ptr = 0;
- fputs (output, stdout);
- *ptr = 0x1b;
- }
- while (!done)
- {
- if (memcmp (ptr, "\x1b[0m", 4) == 0)
- {
- new_attr = org_attr;
- n_ctrl = 4;
- }
- else if (memcmp (ptr, "\x1b[01;31m", 8) == 0)
- {
- new_attr = FOREGROUND_INTENSITY | FOREGROUND_RED;
- n_ctrl = 8;
- }
- else if (memcmp (ptr, "\x1b[01;32m", 8) == 0)
- {
- new_attr = FOREGROUND_INTENSITY | FOREGROUND_GREEN;
- n_ctrl = 8;
- }
- else if (memcmp (ptr, "\x1b[01;33m", 8) == 0) // bright yellow
- {
- new_attr = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN;
- n_ctrl = 8;
- }
- else if (memcmp (ptr, "\x1b[31;41m", 8) == 0)
- {
- new_attr = FOREGROUND_RED | BACKGROUND_RED;
- n_ctrl = 8;
- }
- else if (memcmp (ptr, "\x1b[32;42m", 8) == 0)
- {
- new_attr = FOREGROUND_GREEN | BACKGROUND_GREEN;
- n_ctrl = 8;
- }
- else if (memcmp (ptr, "\x1b[30;41m", 8) == 0) // 30 = foreground black
- {
- new_attr = BACKGROUND_RED;
- n_ctrl = 8;
- }
- else if (memcmp (ptr, "\x1b[30;42m", 8) == 0)
- {
- new_attr = BACKGROUND_GREEN;
- n_ctrl = 8;
- }
- else if (*ptr == 0x1b)
- {
- new_attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
- SetConsoleTextAttribute (stdout_handle, new_attr);
- printf ("\n"
- "INTERNAL WARNING: vprintf2() encountered an unsupported ANSI escape sequence\n"
- " Please send a bug report\n");
- n_ctrl = 0;
- }
- SetConsoleTextAttribute (stdout_handle, new_attr);
- ptr2 = strchr (ptr + 1, 0x1b);
- if (ptr2)
- n_print = ptr2 - ptr;
- else
- {
- n_print = strlen (ptr);
- done = 1;
- }
- ptr[n_print] = 0;
- ptr += n_ctrl;
- fputs (ptr, stdout);
- (ptr - n_ctrl)[n_print] = 0x1b;
- ptr = ptr2;
- }
- }
- return n_chars;
- #define printf printf2
- #define fprintf fprintf2
- }
- int
- printf2 (const char *format, ...)
- {
- va_list argptr;
- int n_chars;
- va_start (argptr, format);
- n_chars = vprintf2 (format, argptr);
- va_end (argptr);
- return n_chars;
- }
- int
- fprintf2 (FILE *file, const char *format, ...)
- {
- va_list argptr;
- int n_chars;
- va_start (argptr, format);
- if (file != stdout)
- n_chars = vfprintf (file, format, argptr);
- else
- n_chars = vprintf2 (format, argptr);
- va_end (argptr);
- return n_chars;
- }
- #endif // defined _WIN32 && defined USE_ANSI_COLOR
- void
- clear_line (void)
- /*
- This function is used to fix a problem when using the MinGW or Visual C++ port
- on Windows 98 (probably Windows 95 too) while ANSI.SYS is not loaded.
- If a line contains colors, printed with printf() or fprintf() (actually
- printf2() or fprintf2()), it cannot be cleared by printing spaces on the same
- line. A solution is using SetConsoleTextAttribute(). The problem doesn't occur
- if ANSI.SYS is loaded. It also doesn't occur on Windows XP, even if ANSI.SYS
- isn't loaded. We print 79 spaces (not 80), because in command.com the cursor
- advances to the next line if we print something on the 80th column (in 80
- column mode). This doesn't happen in xterm.
- */
- {
- #if !defined _WIN32 || !defined USE_ANSI_COLOR
- fputs ("\r \r", stdout);
- #else
- WORD org_attr;
- CONSOLE_SCREEN_BUFFER_INFO info;
- HANDLE stdout_handle = GetStdHandle (STD_OUTPUT_HANDLE);
- GetConsoleScreenBufferInfo (stdout_handle, &info);
- org_attr = info.wAttributes;
- SetConsoleTextAttribute (stdout_handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
- fputs ("\r \r", stdout);
- SetConsoleTextAttribute (stdout_handle, org_attr);
- #endif
- }
- int
- ansi_init (void)
- {
- int result = isatty (STDOUT_FILENO);
- #ifdef DJGPP
- if (result)
- {
- // Don't use __MSDOS__, because __dpmi_regs and __dpmi_int are DJGPP specific
- __dpmi_regs reg;
- reg.x.ax = 0x1a00; // DOS 4.0+ ANSI.SYS installation check
- __dpmi_int (0x2f, ®);
- if (reg.h.al != 0xff) // AL == 0xff if installed
- result = 0;
- }
- #endif
- misc_ansi_color = result;
- return result;
- }
- int
- gauge (int percent, int width, char char1, char char2, int color1, int color2)
- {
- int x = 0;
- char buf[1024 + 32]; // 32 == ANSI code buffer
- if (!width || percent < 0 || percent > 100)
- return -1;
- if (width > 1024)
- width = 1024;
- x = (width * percent) / 100;
- memset (buf, char1, x);
- buf[x] = 0;
- if (x < width) // percent < 100
- {
- if (color1 != -1 && color2 != -1)
- sprintf (&buf[x], "\x1b[3%d;4%dm", color1, color1);
- memset (strchr (buf, 0), char2, width - x);
- }
- if (color1 != -1 && color2 != -1) // ANSI?
- {
- buf[width + 8] = 0; // 8 == ANSI code length
- fprintf (stdout, "\x1b[3%d;4%dm%s\x1b[0m", color2, color2, buf);
- }
- else // no ANSI
- {
- buf[width] = 0;
- fputs (buf, stdout);
- }
- return 0;
- }
- #if (defined __unix__ && !defined __MSDOS__) || defined __BEOS__ || \
- defined __APPLE__ // Mac OS X actually
- static int oldtty_set = 0, stdin_tty = 1; // 1 => stdin is a tty, 0 => it's not
- static tty_t oldtty, newtty;
- void
- set_tty (tty_t *param)
- {
- if (stdin_tty && tcsetattr (STDIN_FILENO, TCSANOW, param) == -1)
- {
- fprintf (stderr, "ERROR: Could not set tty parameters\n");
- exit (100);
- }
- }
- /*
- This code compiles with DJGPP, but is not neccesary. Our kbhit() conflicts
- with DJGPP's one, so it won't be used for that function. Perhaps it works
- for making getchar() behave like getch(), but that's a bit pointless.
- */
- void
- init_conio (void)
- {
- if (!isatty (STDIN_FILENO))
- {
- stdin_tty = 0;
- return; // rest is nonsense if not a tty
- }
- if (tcgetattr (STDIN_FILENO, &oldtty) == -1)
- {
- fprintf (stderr, "ERROR: Could not get tty parameters\n");
- exit (101);
- }
- oldtty_set = 1;
- #if 0
- if (register_func (deinit_conio) == -1)
- {
- fprintf (stderr, "ERROR: Could not register function with register_func()\n");
- exit (102);
- }
- #endif
- newtty = oldtty;
- newtty.c_lflag &= ~(ICANON | ECHO);
- newtty.c_lflag |= ISIG;
- newtty.c_cc[VMIN] = 1; // if VMIN != 0, read calls
- newtty.c_cc[VTIME] = 0; // block (wait for input)
- set_tty (&newtty);
- }
- void
- deinit_conio (void)
- {
- if (oldtty_set)
- {
- tcsetattr (STDIN_FILENO, TCSAFLUSH, &oldtty);
- oldtty_set = 0;
- }
- }
- #if defined __CYGWIN__ && !defined USE_POLL
- #warning kbhit() does not work properly in Cygwin executable if USE_POLL is not defined
- #endif
- // this kbhit() conflicts with DJGPP's one
- int
- kbhit (void)
- {
- #ifdef USE_POLL
- struct pollfd fd;
- fd.fd = STDIN_FILENO;
- fd.events = POLLIN;
- fd.revents = 0;
- return poll (&fd, 1, 0) > 0;
- #elif (defined __APPLE__)
- struct timeval tv = { 0L, 0L };
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(0, &fds);
- return select(1, &fds, NULL, NULL, &tv);
- #else
- tty_t tmptty = newtty;
- int ch, key_pressed;
- tmptty.c_cc[VMIN] = 0; // doesn't work as expected on
- set_tty (&tmptty); // Cygwin (define USE_POLL)
- if ((ch = fgetc (stdin)) != EOF)
- {
- key_pressed = 1;
- ungetc (ch, stdin);
- }
- else
- key_pressed = 0;
- set_tty (&newtty);
- return key_pressed;
- #endif
- }
- #elif defined AMIGA // (__unix__ && !__MSDOS__) ||
- int // __BEOS__ ||__APPLE__
- kbhit (void)
- {
- return GetKey () != 0xff ? 1 : 0;
- }
- int
- getch (void)
- {
- BPTR con_fileh;
- int temp;
- con_fileh = Input ();
- // put the console into RAW mode which makes getchar() behave like getch()?
- if (con_fileh)
- SetMode (con_fileh, 1);
- temp = getchar ();
- // put the console out of RAW mode (might make sense)
- if (con_fileh)
- SetMode (con_fileh, 0);
- return temp;
- }
- #endif // AMIGA
- //#define TEST
- #ifdef TEST
- int
- main (int argc, char **argv)
- {
- term_open ();
- printf ("%s%s%s%s%s%s", term_up (), term_up (), term_up (), term_up (), term_up (), term_up ());
- }
- #endif // TEST
|