Пример заголовка и исходного файла, иллюстрирующий способ абстрактного проклятия из приложения. Собирать пыль; написал его более 15 лет назад. Пусть покупатель будет бдителен.
cursemu.h
/***************************************************************************
*
* DO NOT CHANGE ANYTHING BETWEEN THIS LINE AND THE NEXT LINE THAT HAS THE
* WORDS "KLAATU BARRATA NIKTO" ON IT
*
***************************************************************************/
#ifndef X__CURSEMU__H
#define X__CURSEMU__H
#include <stdio.h>
#ifdef linux
#define _POSIX_VERSION
#endif
#ifndef _POSIX_VERSION
#include <sgtty.h>
#define USE_OLD_TTY
#include <sys/ioctl.h>
#undef USE_OLD_TTY
#ifndef CBREAK
#define CBREAK RAW
#endif
#if !defined(sun) && !defined(sequent) && !defined(hpux) && \
!defined(_AIX) && !defined(aix)
#include <strings.h>
#define strchr index
#else
#include <string.h>
#endif
#else
#include <string.h>
#include <termios.h>
#endif
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
/* Keep looking ... */
int _tty_ch;
#ifdef _POSIX_VERSION
struct termios _tty;
tcflag_t _res_iflg,
_res_lflg;
#define cbreak()(_tty.c_lflag&=~ICANON, \
tcsetattr(_tty_ch, TCSANOW, &_tty))
#define noecho()(_tty.c_lflag &= ~(ECHO|ICRNL), \
tcsetattr(_tty_ch, TCSADRAIN, &_tty))
#define savetty()((void) tcgetattr(_tty_ch, &_tty), \
_res_iflg = _tty.c_iflag, _res_lflg = _tty.c_lflag)
#define resetty()(_tty.c_iflag = _res_iflg, _tty.c_lflag = _res_lflg,\
(void) tcsetattr(_tty_ch, TCSADRAIN, &_tty))
#define erasechar()(_tty.c_cc[VERASE])
#else
struct sgttyb _tty;
int _res_flg;
#define cbreak()(_tty.sg_flags|=CBREAK, ioctl(_tty_ch, TIOCSETP, &_tty))
#define noecho()(_tty.sg_flags &= ~(ECHO|CRMOD), \
ioctl(_tty_ch, TIOCSETP, &_tty))
#define savetty()((void) ioctl(_tty_ch, TIOCGETP, &_tty), \
_res_flg = _tty.sg_flags)
#define resetty()(_tty.sg_flags = _res_flg, \
(void) ioctl(_tty_ch, TIOCSETP, &_tty))
#define erasechar()(_tty.sg_erase)
#endif
/* KLAATU BARRATA NIKTO */
#define TERMCAP_LENGTH 1024
struct CtrlSeq
{
char termcap[ TERMCAP_LENGTH ];
int numRows, numCols;
/* These pointers are indexes into the termcap buffer, and represent the
* control sequences neccessary to send to the terminal window to perform
* their appropriately named feature.
*/
char *highlight,
*endMode, /* End highlight mode, and other modes. */
*clearScr,
*clearEol,
*scrollRegion,
*moveCursor,
*deleteRow,
*insertRow,
*saveCursor, /* Save the current cursor position */
*restoreCursor; /* Restore the saved cursor position */
int dumbTerm, /* 1 if the terminal is a dumb terminal */
flush; /* 1 if the emulation should flush stdout */
};
struct CtrlSeq ctrlSeq;
#define DEFAULT_COLS 80
#define DEFAULT_ROWS 24
void ce_flush(int toSet);
void ce_puts(char *str);
void ce_gotoRowCol(int row, int col);
void ce_writeStrRowCol(char *theText, int row, int col);
void ce_writeStr(char *theText);
void ce_writeCharRowCol(char theChar, int row, int col);
void ce_writeChar(char theChar);
void ce_clearScreen(void);
void ce_clearEol(void);
void ce_highlight(int on);
void ce_scrollRegion(int row1, int row2);
void ce_deleteRow(int row);
void ce_insertRow(int row);
void ce_saveCursor(void);
void ce_restoreCursor(void);
int ce_getRows(void);
int ce_getCols(void);
#endif
cursemu.с
#include "cursemu.h"
int putchar_x(int c)
{
return(putchar(c));
}
/* Returns 0 on success, -1 on error
*/
int ce_startCurses(void)
{
char *ptr,
tempBuff[ 1024 ];
int result = 0;
if((ptr = (char *)getenv("TERM")) != NULL)
result = tgetent(tempBuff, ptr);
else
result = tgetent(tempBuff, "vt100");
if(result < 1)
{
perror("FATAL Error: No termcap entry found (even tried vt100)!\n");
return(-1);
}
ptr = ctrlSeq.termcap;
if((ctrlSeq.numCols = tgetnum("co")) == -1)
ctrlSeq.numCols = DEFAULT_COLS;
if((ctrlSeq.numRows = tgetnum("li")) == -1)
ctrlSeq.numRows = DEFAULT_ROWS;
if((ctrlSeq.moveCursor = (char *)tgetstr("cm", &ptr)) == NULL)
ctrlSeq.moveCursor = (char *)tgetstr("cl", &ptr);
if((ctrlSeq.highlight = (char *)tgetstr("mr", &ptr)) == NULL)
ctrlSeq.highlight = (char *)tgetstr("md", &ptr);
ctrlSeq.endMode = (char *)tgetstr("me", &ptr);
ctrlSeq.clearEol = (char *)tgetstr("ce", &ptr);
ctrlSeq.clearScr = (char *)tgetstr("cl", &ptr);
ctrlSeq.scrollRegion = (char *)tgetstr("cs", &ptr);
ctrlSeq.deleteRow = (char *)tgetstr("dl", &ptr);
ctrlSeq.insertRow = (char *)tgetstr("al", &ptr);
ctrlSeq.saveCursor = (char *)tgetstr("sc", &ptr);
ctrlSeq.restoreCursor = (char *)tgetstr("rc", &ptr);
ctrlSeq.dumbTerm = (ctrlSeq.moveCursor == NULL) ||
(ctrlSeq.scrollRegion == NULL) ||
(ctrlSeq.saveCursor == NULL) ||
(ctrlSeq.restoreCursor == NULL) ||
(ctrlSeq.clearEol == NULL);
ctrlSeq.flush = 1;
if(!ctrlSeq.dumbTerm)
{
if((_tty_ch = open("/dev/tty", O_RDWR, 0)) == -1)
_tty_ch = 0;
savetty();
cbreak();
noecho();
return(0);
}
return(-1);
}
int ce_endCurses(void)
{
ce_scrollRegion(-1, -1);
ce_gotoRowCol(ce_getRows() - 1, 0);
resetty();
}
void ce_flush(int toSet)
{
ctrlSeq.flush = toSet;
if(toSet == 1)
fflush(stdout);
}
void ce_puts(char *str)
{
tputs(str, 0, putchar_x);
if(ctrlSeq.flush)
fflush(stdout);
}
void ce_gotoRowCol(int row, int col)
{
if(row > ctrlSeq.numRows)
row = ctrlSeq.numRows;
if(col > ctrlSeq.numCols)
col = ctrlSeq.numCols;
ce_puts((char *)tgoto(ctrlSeq.moveCursor, col, row));
}
void ce_writeStrRowCol(char *theText, int row, int col)
{
ce_flush(0);
ce_gotoRowCol(row, col);
ce_writeStr(theText);
ce_flush(1);
}
void ce_writeStr(char *theText)
{
ce_flush(0);
printf("%s", theText);
ce_flush(1);
}
void ce_writeCharRowCol(char theChar, int row, int col)
{
ce_flush(0);
ce_gotoRowCol(row, col);
ce_writeChar(theChar);
ce_flush(1);
}
void ce_writeChar(char theChar)
{
ce_flush(0);
printf("%c", theChar);
ce_flush(1);
}
void ce_clearScreen(void)
{
ce_puts(ctrlSeq.clearScr);
}
void ce_clearEol(void)
{
ce_puts(ctrlSeq.clearEol);
}
void ce_highlight(int on)
{
if(on == 0)
ce_puts(ctrlSeq.endMode);
else
ce_puts(ctrlSeq.highlight);
}
void ce_scrollRegion(int row1, int row2)
{
ce_puts((char *)tgoto(ctrlSeq.scrollRegion, row1, row2));
}
void ce_deleteRow(int row)
{
ce_gotoRowCol(row, 0);
ce_puts(ctrlSeq.deleteRow);
}
void ce_insertRow(int row)
{
ce_gotoRowCol(row, 0);
ce_puts(ctrlSeq.insertRow);
}
void ce_saveCursor(void)
{
ce_puts(ctrlSeq.saveCursor);
}
void ce_restoreCursor(void)
{
ce_puts(ctrlSeq.restoreCursor);
}
int ce_getRows(void)
{
return(ctrlSeq.numRows);
}
int ce_getCols(void)
{
return(ctrlSeq.numCols);
}
Компиляция
Требуется:
gcc -o cursemu.o -lcurses -ltermcap
Я согласен с тем, что вы сказали о Ncurses быть удивительно, но добро пожаловать в OSX (есть Ncurses порт), но как делать такие программы, как emacs (установленный по умолчанию) работает без него? –
OS X (по крайней мере, моя OS X) имеет ncurses, установленные по умолчанию. –
Ну, похоже, я мог бы также углубиться в документацию ncurses .... спасибо за вашу помощь! –