1599 lines
37 KiB
C
1599 lines
37 KiB
C
/*
|
|
|
|
YABASIC --- a simple Basic Interpreter
|
|
written by Marc-Oliver Ihm 1995-2004
|
|
homepage: www.yabasic.de
|
|
|
|
io.c --- code for screen and file i/o
|
|
|
|
This file is part of yabasic and may be copied only
|
|
under the terms of either the Artistic License or
|
|
the GNU General Public License (GPL), both of which
|
|
can be found at www.yabasic.de
|
|
|
|
*/
|
|
|
|
|
|
/* ------------- defines ---------------- */
|
|
|
|
#ifdef WINDOWS
|
|
#define WM_WANTKEY (WM_APP+7)
|
|
#endif
|
|
|
|
/* ------------- includes ---------------- */
|
|
|
|
#ifndef YABASIC_INCLUDED
|
|
#include "yabasic.h" /* all prototypes and structures */
|
|
#endif
|
|
|
|
|
|
/* ------------- local defines ----------------- */
|
|
|
|
#define YC_BLACK 0
|
|
#define YC_WHITE 1
|
|
#define YC_RED 2
|
|
#define YC_BLUE 3
|
|
#define YC_GREEN 4
|
|
#define YC_YELLOW 5
|
|
#define YC_CYAN 6
|
|
#define YC_MAGENTA 7
|
|
|
|
#ifndef COLOR_BLACK
|
|
#define COLOR_BLACK 0
|
|
#define COLOR_RED 1
|
|
#define COLOR_GREEN 2
|
|
#define COLOR_YELLOW 3
|
|
#define COLOR_BLUE 4
|
|
#define COLOR_MAGENTA 5
|
|
#define COLOR_CYAN 6
|
|
#define COLOR_WHITE 7
|
|
#endif
|
|
#ifndef A_COLOR
|
|
#define A_COLOR 0xff00
|
|
#endif
|
|
|
|
/* ------------- external references ---------------- */
|
|
|
|
extern int mylineno; /* current line number */
|
|
extern int yyparse(); /* call bison parser */
|
|
|
|
|
|
/* ------------- local functions ---------------- */
|
|
|
|
static int onechar(void); /* read one char from currentinstream */
|
|
static void backchar(int); /* put char back into stream */
|
|
static void readline(void); /* read one line from current stream */
|
|
static void curinit(void); /* initialize curses */
|
|
static void initcol(void); /* initialize curses colors */
|
|
void myswitch(int); /* switch to specified stream */
|
|
int checkstream(void); /* test if currst is still valid */
|
|
#ifdef WINDOWS
|
|
static DWORD keythread(LPWORD); /* wait for key input from console */
|
|
static int is_valid_key(INPUT_RECORD *); /* check if input rec is valid key */
|
|
#endif
|
|
int name2yc(char *); /* convert a color name to an integer */
|
|
int yc2oc(int,int); /* convert a yabasic color to operating system color */
|
|
char *yc2short(int); /* convert yabasic colours to short colour name */
|
|
#ifdef UNIX
|
|
int oc2yc(int); /* convert an operating system color to yabasic color */
|
|
#endif
|
|
|
|
/* ------------- global variables ---------------- */
|
|
|
|
static int prompted; /* TRUE, if prompt is fresh */
|
|
int read_controls; /* TRUE, if input should read control characters */
|
|
FILE *streams[FOPEN_MAX]; /* file streams */
|
|
int stream_modes[FOPEN_MAX]; /* modes for streams */
|
|
int lprstream=-1; /* stream associated with lineprinter */
|
|
static int currstr=STDIO_STREAM; /* currently switched stream */
|
|
static FILE *cinstr; /* current stream for input */
|
|
static FILE *coutstr; /* current stream for output */
|
|
static char linebuffer[INBUFFLEN]; /* buffer for one line of input */
|
|
int curinized=FALSE; /* true, if curses has been initialized */
|
|
static char *currchar; /* current char to read */
|
|
static short stdfc; /* standard foreground color of window */
|
|
static short stdbc; /* standard background color of window */
|
|
#ifdef UNIX
|
|
int winpid=-1; /* pid of process waiting for window keys */
|
|
int termpid=-1; /* pid of process waiting for terminal keys */
|
|
FILE *lineprinter=NULL; /* handle for line printer */
|
|
#ifndef BUILD_NCURSES
|
|
int COLS = 80;
|
|
int LINES = 25;
|
|
#endif
|
|
#else
|
|
HANDLE wantkey=INVALID_HANDLE_VALUE; /* mutex to signal key desire */
|
|
HANDLE gotkey=INVALID_HANDLE_VALUE; /* mutex to signal key reception */
|
|
HANDLE wthandle=INVALID_HANDLE_VALUE; /* handle of win thread */
|
|
HANDLE kthandle=INVALID_HANDLE_VALUE; /* handle of inkey thread */
|
|
DWORD ktid; /* id of inkey thread */
|
|
int LINES=0; /* number of lines on screen */
|
|
int COLS=0; /* number of columns on screen */
|
|
HANDLE ConsoleInput; /* handle for console input */
|
|
HANDLE ConsoleOutput; /* handle for console output */
|
|
HANDLE lineprinter=INVALID_HANDLE_VALUE; /* handle for line printer */
|
|
#endif
|
|
|
|
|
|
/* ------------- functions ---------------- */
|
|
|
|
void create_print(char type) /* create command 'print' */
|
|
{
|
|
struct command *cmd;
|
|
|
|
cmd=add_command(cPRINT,NULL);
|
|
cmd->pointer=my_malloc(sizeof(int));
|
|
/* store type of print */
|
|
cmd->tag=type;
|
|
}
|
|
|
|
|
|
void print(struct command *cmd) /* print on screen */
|
|
{
|
|
int type;
|
|
struct stackentry *p,*q,*r;
|
|
static int last='n';
|
|
char *s;
|
|
int x,y;
|
|
long int n;
|
|
double d;
|
|
#ifdef WINDOWS
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
SMALL_RECT screen;
|
|
COORD to;
|
|
CHAR_INFO ci;
|
|
#endif
|
|
|
|
r=NULL;
|
|
type=cmd->tag;
|
|
if (!checkstream()) return;
|
|
switch(type) {
|
|
case 'n': /* print newline */
|
|
if (curinized && coutstr==stdout) {
|
|
#ifdef WINDOWS
|
|
GetConsoleScreenBufferInfo(ConsoleOutput,&csbi);
|
|
x=csbi.dwCursorPosition.X;
|
|
y=csbi.dwCursorPosition.Y;
|
|
if (y>=LINES-1) {
|
|
screen.Left=0;
|
|
screen.Right=COLS;
|
|
screen.Top=1;
|
|
screen.Bottom=LINES;
|
|
to.X=0;
|
|
to.Y=0;
|
|
ci.Char.AsciiChar=' ';
|
|
ci.Attributes=FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED;
|
|
ScrollConsoleScreenBuffer(ConsoleOutput,&screen,NULL,to,&ci);
|
|
to.X=0;
|
|
to.Y=y;
|
|
} else {
|
|
to.X=0;
|
|
to.Y=y+1;
|
|
}
|
|
SetConsoleCursorPosition(ConsoleOutput,to);
|
|
break;
|
|
#else
|
|
#ifdef BUILD_NCURSES
|
|
getyx(stdscr,y,x);
|
|
if (y>=LINES-1) {
|
|
scrl(1);
|
|
y=y-1;
|
|
}
|
|
move(y+1,0);
|
|
refresh();
|
|
#endif
|
|
break;
|
|
#endif
|
|
} else {
|
|
string[0]='\n';
|
|
if (abs(currstr)==lprstream) {
|
|
string[1]='\r';
|
|
string[2]='\0';
|
|
} else {
|
|
string[1]='\0';
|
|
}
|
|
}
|
|
onestring(string);
|
|
break;
|
|
case 't': /* print tab */
|
|
string[0]='\t';
|
|
string[1]='\0';
|
|
onestring(string);
|
|
break;
|
|
case 'd': /* print double value */
|
|
p=pop(stNUMBER);
|
|
d=p->value;
|
|
n=(int)d;
|
|
if (n==d && d<LONG_MAX && d>LONG_MIN)
|
|
sprintf(string,"%s%ld",(last=='d')?" ":"",n);
|
|
else
|
|
sprintf(string,"%s%g",(last=='d')?" ":"",d);
|
|
onestring(string);
|
|
break;
|
|
case 'U':
|
|
r=pop(stSTRING);
|
|
case 'u': /* print using */
|
|
p=pop(stSTRING);
|
|
q=pop(stNUMBER);
|
|
type='d';
|
|
s=string;
|
|
if (last=='d') {
|
|
*s=' ';
|
|
s++;
|
|
}
|
|
if (!myformat(s,q->value,p->pointer,r?r->pointer:NULL)) {
|
|
sprintf(string,"'%s' is not a valid format",(char *)p->pointer);
|
|
error(ERROR,string);
|
|
break;
|
|
}
|
|
onestring(string);
|
|
break;
|
|
case 's':
|
|
p=pop(stSTRING);
|
|
onestring((char *)p->pointer);
|
|
break;
|
|
}
|
|
last=type;
|
|
}
|
|
|
|
|
|
void mymove() /* move to specific position on screen */
|
|
{
|
|
#ifdef BUILD_NCURSES
|
|
int x,y;
|
|
#ifdef WINDOWS
|
|
COORD coord;
|
|
#endif
|
|
|
|
y=(int)pop(stNUMBER)->value;
|
|
if (y<0) y=0;
|
|
if (y>LINES-1) y=LINES-1;
|
|
x=(int)pop(stNUMBER)->value;
|
|
if (x<0) x=0;
|
|
if (x>COLS-1) x=COLS-1;
|
|
if (!curinized) {
|
|
error(ERROR,"need to call 'clear screen' first");
|
|
return;
|
|
}
|
|
#ifdef UNIX
|
|
move(y,x);
|
|
refresh();
|
|
#else
|
|
coord.X=x;
|
|
coord.Y=y;
|
|
SetConsoleCursorPosition(ConsoleOutput,coord);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
void clearscreen() /* clear entire screen */
|
|
{
|
|
#ifdef WINDOWS
|
|
DWORD written; /* number of chars actually written */
|
|
COORD coord; /* coordinates to start writing */
|
|
#endif
|
|
|
|
if (!curinized) curinit();
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
clear();
|
|
refresh();
|
|
#else
|
|
error(ERROR,"ncurses support was not compiled!");
|
|
#endif
|
|
#else
|
|
coord.X=0;
|
|
coord.Y=0;
|
|
FillConsoleOutputCharacter(ConsoleOutput,' ',LINES*COLS,coord,&written);
|
|
FillConsoleOutputAttribute(ConsoleOutput,
|
|
FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE,
|
|
LINES*COLS,
|
|
coord,&written);
|
|
SetConsoleCursorPosition(ConsoleOutput,coord);
|
|
#endif
|
|
}
|
|
|
|
|
|
static void curinit(void) /* initialize curses */
|
|
{
|
|
#ifdef WINDOWS
|
|
CONSOLE_SCREEN_BUFFER_INFO coninfo; /* receives console size */
|
|
#endif
|
|
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
initscr();
|
|
initcol();
|
|
setscrreg(0,LINES);
|
|
scrollok(stdscr,TRUE);
|
|
leaveok(stdscr,TRUE);
|
|
keypad(stdscr,TRUE);
|
|
intrflush(stdscr,FALSE);
|
|
curs_set(0);
|
|
def_prog_mode();
|
|
#endif
|
|
#else
|
|
GetConsoleScreenBufferInfo(ConsoleOutput,&coninfo);
|
|
COLS=coninfo.dwSize.X;
|
|
LINES=coninfo.dwSize.Y;
|
|
#endif
|
|
curinized=TRUE;
|
|
}
|
|
|
|
|
|
char *inkey(double maxtime) /* get char from keyboard */
|
|
{
|
|
char *skey;
|
|
#ifdef WINDOWS
|
|
int ms; /* number of milliseconds to wait*/
|
|
DWORD oflags; /* saves normal state of console input buffer */
|
|
DWORD flags; /* new input mode for console input buffer */
|
|
static char conkeybuff[100],winkeybuff[100];
|
|
#else
|
|
fd_set readfds;
|
|
struct timeval tv;
|
|
int maxfd;
|
|
int winfd[2],termfd[2];
|
|
char retkey[100];
|
|
int status,ret;
|
|
#endif
|
|
|
|
|
|
if (maxtime>=0.0 && maxtime<0.01) maxtime=0.01;
|
|
if (!curinized) {
|
|
error(ERROR,"need to call 'clear screen' first");
|
|
return my_strdup("");
|
|
}
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
retkey[0]='\0';
|
|
winfd[0]=winfd[1]=termfd[0]=termfd[1]=-1;
|
|
winpid=termpid=-1;
|
|
if (pipe(winfd) || pipe(termfd)) {
|
|
error(ERROR,"Couldn't open pipes");
|
|
goto sane_state;
|
|
}
|
|
|
|
winpid=fork();
|
|
if (winpid==0) {
|
|
/* this is the child */
|
|
signal(SIGINT,SIG_DFL);
|
|
signal(SIGFPE,SIG_DFL);
|
|
signal(SIGSEGV,SIG_DFL);
|
|
retkey[0]='\0';
|
|
#ifndef BEOS
|
|
if (winopened) getwinkey(retkey);
|
|
#endif
|
|
if (*retkey) write(winfd[1],retkey,strlen(retkey));
|
|
wait(&status);
|
|
exit(0);
|
|
} else if (winpid==-1) {
|
|
error(ERROR,"couldn't fork child");
|
|
goto sane_state;
|
|
}
|
|
|
|
termpid=fork();
|
|
if (termpid==0) {
|
|
/* this is the child */
|
|
signal(SIGINT,SIG_DFL);
|
|
signal(SIGFPE,SIG_DFL);
|
|
signal(SIGSEGV,SIG_DFL);
|
|
retkey[0]='\0';
|
|
noecho();
|
|
cbreak();
|
|
timeout(-1);
|
|
gettermkey(retkey);
|
|
if (*retkey) write(termfd[1],retkey,strlen(retkey));
|
|
wait(&status);
|
|
exit(0);
|
|
} else if (termpid==-1) {
|
|
error(ERROR,"Couldn't fork child");
|
|
goto sane_state;
|
|
}
|
|
|
|
FD_ZERO(&readfds);
|
|
FD_SET(termfd[0],&readfds);
|
|
FD_SET(winfd[0],&readfds);
|
|
fflush(stdout);
|
|
maxfd=(termfd[0]>winfd[0])?termfd[0]:winfd[0];
|
|
if (maxtime>=0) {
|
|
tv.tv_sec=(int)maxtime;
|
|
tv.tv_usec=(maxtime-(int)maxtime)*1000000.;
|
|
ret=select(maxfd+1,&readfds,NULL,NULL,&tv);
|
|
} else {
|
|
ret=select(maxfd+1,&readfds,NULL,NULL,NULL);
|
|
}
|
|
if (ret==-1) {
|
|
error(ERROR,"select failed");
|
|
goto sane_state;
|
|
}
|
|
|
|
if (FD_ISSET(termfd[0],&readfds)) {
|
|
ret=read(termfd[0],retkey,100);
|
|
} else if (FD_ISSET(winfd[0],&readfds)) {
|
|
ret=read(winfd[0],retkey,100);
|
|
// if (!strncmp("MB",retkey,2)) getmousexybm(retkey,&mousex,&mousey,&mouseb,&mousemod);
|
|
}
|
|
else ret=0;
|
|
retkey[ret]='\0';
|
|
sane_state:
|
|
skey=retkey;
|
|
if (winfd[0]>0) close(winfd[0]);
|
|
if (winfd[1]>0) close(winfd[1]);
|
|
if (termfd[0]>0) close(termfd[0]);
|
|
if (termfd[1]>0) close(termfd[1]);
|
|
if (termpid>0) {
|
|
kill(termpid,SIGTERM);
|
|
waitpid(termpid,&status,0);
|
|
termpid=-1;
|
|
}
|
|
if (winpid>0) {
|
|
kill(winpid,SIGTERM);
|
|
waitpid(winpid,&status,0);
|
|
winpid=-1;
|
|
}
|
|
reset_prog_mode(); /* prepare for input afterwards */
|
|
#endif
|
|
#elif WINDOWS
|
|
/* create event to signal key */
|
|
if (gotkey==INVALID_HANDLE_VALUE) gotkey=CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
if (wantkey==INVALID_HANDLE_VALUE) wantkey=CreateEvent(NULL,TRUE,FALSE,NULL);
|
|
|
|
conkeybuff[0]=winkeybuff[0]='\0';
|
|
|
|
GetConsoleMode(ConsoleInput,&oflags);
|
|
flags=oflags&~(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT);
|
|
SetConsoleMode(ConsoleInput,flags);
|
|
|
|
/* create thread to observe console */
|
|
if (kthandle==INVALID_HANDLE_VALUE) {
|
|
kthandle=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)keythread,
|
|
(LPVOID)conkeybuff,0,(LPDWORD)&ktid);
|
|
}
|
|
/* signal, that we want a key */
|
|
if (winopened) {
|
|
SendMessage(window,WM_WANTKEY,0,(LPARAM)winkeybuff);
|
|
}
|
|
SetEvent(wantkey);
|
|
ms=(int)(1000*maxtime);
|
|
if (ms<0)
|
|
WaitForSingleObject(gotkey,INFINITE);
|
|
else
|
|
WaitForSingleObject(gotkey,ms);
|
|
|
|
ResetEvent(wantkey);
|
|
SetConsoleMode(ConsoleInput,oflags);
|
|
if (*winkeybuff)
|
|
skey=winkeybuff;
|
|
else
|
|
skey=conkeybuff;
|
|
#endif
|
|
return my_strdup(skey);
|
|
}
|
|
|
|
|
|
#ifdef WINDOWS
|
|
static DWORD keythread(LPWORD lparam) /* wait for key input from console */
|
|
{
|
|
INPUT_RECORD inrec; /* for reading key-event */
|
|
int key,skey;
|
|
int num;
|
|
char *keybuff;
|
|
HANDLE evn[2];
|
|
|
|
keybuff=(char *)lparam;
|
|
keybuff[0]='\0';
|
|
evn[0]=wantkey;
|
|
evn[1]=ConsoleInput;
|
|
do {
|
|
do {
|
|
do {
|
|
WaitForMultipleObjects(2,evn,TRUE,INFINITE);
|
|
ReadConsoleInput(ConsoleInput,&inrec,1,&num);
|
|
} while(!is_valid_key(&inrec));
|
|
if (isprint(inrec.Event.KeyEvent.uChar.AsciiChar)) {
|
|
keybuff[0]=inrec.Event.KeyEvent.uChar.AsciiChar;
|
|
keybuff[1]='\0';
|
|
} else {
|
|
key=inrec.Event.KeyEvent.wVirtualKeyCode;
|
|
skey=-1;
|
|
switch(key) {
|
|
case 0x1b: skey=kESC;break;
|
|
case 0x0d: skey=kENTER;break;
|
|
case 0x09: skey=kTAB;break;
|
|
case 0x21: skey=kSCRNUP;break;
|
|
case 0x22: skey=kSCRNDOWN;break;
|
|
case 0x70: skey=kF1;break;
|
|
case 0x71: skey=kF2;break;
|
|
case 0x72: skey=kF3;break;
|
|
case 0x73: skey=kF4;break;
|
|
case 0x74: skey=kF5;break;
|
|
case 0x75: skey=kF6;break;
|
|
case 0x76: skey=kF7;break;
|
|
case 0x77: skey=kF8;break;
|
|
case 0x78: skey=kF9;break;
|
|
case 0x79: skey=kF10;break;
|
|
case 0x7a: skey=kF11;break;
|
|
case 0x7b: skey=kF12;break;
|
|
case 0x24: skey=kHOME;break;
|
|
case 0x23: skey=kEND;break;
|
|
case 0x2d: skey=kINS;break;
|
|
case 0x2e: skey=kDEL;break;
|
|
case 0x08: skey=kBACKSPACE;break;
|
|
case 0x27: skey=kRIGHT;break;
|
|
case 0x25: skey=kLEFT;break;
|
|
case 0x28: skey=kDOWN;break;
|
|
case 0x26: skey=kUP;break;
|
|
default:
|
|
sprintf(keybuff,"key%x",key);
|
|
}
|
|
if (skey>0) strcpy(keybuff,ykey[skey]);
|
|
}
|
|
if (!keybuff[0]) printf("Loop !\n");
|
|
} while(!keybuff[0]);
|
|
ResetEvent(wantkey);
|
|
SetEvent(gotkey);
|
|
}while(TRUE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int is_valid_key(INPUT_RECORD *rec) /* check if input rec contains valid key */
|
|
{
|
|
if (rec->EventType!=KEY_EVENT ||
|
|
!rec->Event.KeyEvent.bKeyDown ||
|
|
rec->Event.KeyEvent.wVirtualKeyCode==VK_SHIFT ||
|
|
rec->Event.KeyEvent.wVirtualKeyCode==VK_CONTROL) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
char *replace(char *string) /* replace \n,\a, etc. */
|
|
{
|
|
char *from,*to;
|
|
char *p;
|
|
int val;
|
|
static char *hexdigits="0123456789abcdef";
|
|
|
|
from=to=string;
|
|
while(*from) {
|
|
if (*from=='\\') {
|
|
from++;
|
|
switch(*from) {
|
|
case 'n': *to='\n';break;
|
|
case 't': *to='\t';break;
|
|
case 'v': *to='\v';break;
|
|
case 'b': *to='\b';break;
|
|
case 'r': *to='\r';break;
|
|
case 'f': *to='\f';break;
|
|
case 'a': *to='\a';break;
|
|
case '\\': *to='\\';break;
|
|
case '\?': *to='\?';break;
|
|
case '\'': *to='\'';break;
|
|
case '\"': *to='\"';break;
|
|
case 'x':
|
|
val=0;
|
|
if ((p=strchr(hexdigits,tolower(*(from+1)))) && p-hexdigits<16) {
|
|
from++;
|
|
val=p-hexdigits;
|
|
if ((p=strchr(hexdigits,tolower(*(from+1)))) && p-hexdigits<16) {
|
|
from++;
|
|
val*=16;
|
|
val+=p-hexdigits;
|
|
}
|
|
}
|
|
*to=(char)val;
|
|
break;
|
|
default:
|
|
*to='\\';
|
|
to++;
|
|
*to=*from;
|
|
}
|
|
}
|
|
else
|
|
*to=*from;
|
|
from++;
|
|
to++;
|
|
}
|
|
*to='\0';
|
|
return string;
|
|
}
|
|
|
|
|
|
void create_myopen(int num) /* create command 'myopen' */
|
|
{
|
|
struct command *cmd;
|
|
|
|
cmd=add_command(cOPEN,NULL);
|
|
cmd->tag=num;
|
|
}
|
|
|
|
|
|
void myopen(struct command *cmd) /* open specified file for given name */
|
|
{
|
|
#ifdef WINDOWS
|
|
char PrinterName[200]; /* Name of default Printer */
|
|
char *n; /* points into PrinterName */
|
|
DOC_INFO_1 di;
|
|
#endif
|
|
FILE *handle=NULL;
|
|
int stream,i;
|
|
char *name=NULL;
|
|
char *mode=NULL;
|
|
char **pmode;
|
|
static char *valid_modes[]={"r+","r","w","a","rb","wb","ab",""};
|
|
static int smodes[]={smREADWRITE,smREAD,smWRITE,smWRITE,smREAD,smWRITE,smWRITE,smREAD};
|
|
int smode;
|
|
|
|
struct stackentry *p;
|
|
int has_mode,has_stream,printer=0;
|
|
/* decode cmd->tag */
|
|
has_stream=cmd->tag&OPEN_HAS_STREAM;
|
|
has_mode=cmd->tag&OPEN_HAS_MODE;
|
|
/* printer=cmd->tag&OPEN_PRINTER;*/
|
|
|
|
if (has_mode)
|
|
mode=my_strdup(pop(stSTRING)->pointer);
|
|
else
|
|
mode=printer ? my_strdup("w") : my_strdup("r");
|
|
if (printer)
|
|
name=my_strdup("/usr/bin/lpr");
|
|
else
|
|
name=my_strdup(pop(stSTRING)->pointer);
|
|
|
|
if (has_stream) {
|
|
stream=(int)pop(stNUMBER)->value;
|
|
} else {
|
|
stream=0;
|
|
for(i=1;i<FOPEN_MAX-4;i++) {
|
|
if (stream_modes[i]==smCLOSED) {
|
|
stream=i;
|
|
break;
|
|
}
|
|
}
|
|
if (!stream) {
|
|
sprintf(errorstring,"reached maximum number of open files");
|
|
errorcode=5;
|
|
goto open_done;
|
|
}
|
|
}
|
|
|
|
p=push();
|
|
p->value=0.;
|
|
p->type=stNUMBER;
|
|
|
|
/*
|
|
if (printer && print_to_file) {
|
|
sprintf(errorstring,"cannot open printer: already printing grafics");
|
|
errorcode=6;
|
|
goto open_done;
|
|
}*/
|
|
|
|
if (badstream(stream,1)) {
|
|
sprintf(errorstring,"invalid stream number %d",stream);
|
|
errorcode=9;
|
|
goto open_done;
|
|
}
|
|
if (stream_modes[stream]!=smCLOSED) {
|
|
sprintf(errorstring,"stream already in use");
|
|
errorcode=2;
|
|
goto open_done;
|
|
}
|
|
|
|
smode=0;
|
|
for(pmode=valid_modes;**pmode;pmode++) {
|
|
if (!strcmp(*pmode,mode)) break;
|
|
smode++;
|
|
}
|
|
if (!**pmode) {
|
|
sprintf(errorstring,"\'%s\' is not a valid filemode",mode);
|
|
errorcode=3;
|
|
goto open_done;
|
|
}
|
|
|
|
if (printer) {
|
|
#ifdef UNIX
|
|
lineprinter=popen(name,"w");
|
|
if (!lineprinter) {
|
|
sprintf(errorstring,"could not open line printer");
|
|
errorcode=7;
|
|
goto open_done;
|
|
}
|
|
#else
|
|
/* query win.ini for default printer */
|
|
GetProfileString("windows","device",",,,",PrinterName,200);
|
|
|
|
/* truncate printer name */
|
|
n=PrinterName;
|
|
while(*n && *n!=',') n++;
|
|
*n='\0';
|
|
|
|
OpenPrinter(PrinterName,&lineprinter,NULL);
|
|
di.pDocName="yabasic text";
|
|
di.pOutputFile=(LPTSTR)NULL;
|
|
di.pDatatype="RAW";
|
|
if (!StartDocPrinter(lineprinter,1,(LPBYTE)&di)) {
|
|
sprintf(errorstring,"could not open line printer");
|
|
errorcode=7;
|
|
goto open_done;
|
|
}
|
|
StartPagePrinter(lineprinter);
|
|
#endif
|
|
lprstream=stream;
|
|
} else {
|
|
handle=fopen(name,mode);
|
|
if (handle==NULL) {
|
|
sprintf(errorstring,"could not open '%s': %s",name,my_strerror(errno));
|
|
errorcode=4;
|
|
goto open_done;
|
|
}
|
|
streams[stream]=handle;
|
|
}
|
|
stream_modes[stream]=smodes[smode];
|
|
errorcode=0;
|
|
p->value=stream;
|
|
open_done:
|
|
if (name) my_free(name);
|
|
if (mode) my_free(mode);
|
|
}
|
|
|
|
|
|
void checkopen(void) /* check, if open has been sucessfull */
|
|
{
|
|
double result;
|
|
|
|
result=pop(stNUMBER)->value;
|
|
if (result<=0) {
|
|
error(ERROR,errorstring);
|
|
}
|
|
}
|
|
|
|
|
|
void myclose(void) /* close the specified stream */
|
|
{
|
|
int s;
|
|
#ifdef WINDOWS
|
|
DWORD written;
|
|
#endif
|
|
|
|
s=(int)pop(stNUMBER)->value;
|
|
if (s == -2){
|
|
for(s=1;s<FOPEN_MAX-4;s++) {
|
|
if (stream_modes[s]!=smCLOSED) {
|
|
streams[s]=NULL;
|
|
stream_modes[s]=smCLOSED;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (abs(s)==STDIO_STREAM || badstream(s,0)) return;
|
|
if (stream_modes[s]==smCLOSED) {
|
|
sprintf(string,"stream %d already closed",s);
|
|
error(WARNING,string);
|
|
return;
|
|
}
|
|
|
|
|
|
if (s==lprstream) {
|
|
#ifdef UNIX
|
|
pclose(lineprinter);
|
|
#else
|
|
WritePrinter(lineprinter,"\f",2,&written);
|
|
EndPagePrinter(lineprinter);
|
|
EndDocPrinter(lineprinter);
|
|
ClosePrinter(lineprinter);
|
|
lineprinter=INVALID_HANDLE_VALUE;
|
|
#endif
|
|
lprstream=-1;
|
|
} else {
|
|
fclose(streams[s]);
|
|
}
|
|
streams[s]=NULL;
|
|
stream_modes[s]=smCLOSED;
|
|
}
|
|
|
|
|
|
void myseek(struct command *cmd) /* reposition file pointer */
|
|
{
|
|
int s,p,m,i;
|
|
struct stackentry *pp;
|
|
char *mode;
|
|
|
|
if (cmd->type==cSEEK2)
|
|
mode=(char *)my_strdup(pop(stSTRING)->pointer);
|
|
else
|
|
mode=my_strdup("begin");
|
|
p=(int)pop(stNUMBER)->value;
|
|
s=(int)pop(stNUMBER)->value;
|
|
pp=push();
|
|
pp->value=0.;
|
|
pp->type=stNUMBER;
|
|
for(i=0;mode[i];i++) mode[i]=tolower(mode[i]);
|
|
if (!strcmp(mode,"begin")) {
|
|
m=SEEK_SET;
|
|
} else if (!strcmp(mode,"end")) {
|
|
m=SEEK_END;
|
|
} else if (!strcmp(mode,"here")) {
|
|
m=SEEK_CUR;
|
|
} else {
|
|
sprintf(errorstring,"seek mode '%s' is none of begin,end,here",mode);
|
|
errorcode=12;
|
|
my_free(mode);
|
|
return;
|
|
}
|
|
my_free(mode);
|
|
if (abs(s)==STDIO_STREAM || badstream(s,0)) return;
|
|
if (!(stream_modes[s] & (smREAD | smWRITE | smREADWRITE))) {
|
|
sprintf(errorstring,"stream %d not open",s);
|
|
errorcode=11;
|
|
return;
|
|
}
|
|
if (fseek(streams[s],(long)p,m)) {
|
|
sprintf(errorstring,"could not position stream %d to byte %d",s,p);
|
|
errorcode=10;
|
|
return;
|
|
}
|
|
pp->value=1.0;
|
|
}
|
|
|
|
|
|
void create_pps(int type,int input) /* create command pushswitch or popswitch */
|
|
{
|
|
struct command *cmd;
|
|
|
|
cmd=add_command(type,NULL);
|
|
cmd->args=input;
|
|
}
|
|
|
|
|
|
void push_switch(struct command *cmd) /* push current stream on stack and switch to new one */
|
|
{
|
|
static int oldstream=STDIO_STREAM;
|
|
struct stackentry *s;
|
|
int stream;
|
|
|
|
stream=(int)pop(stNUMBER)->value;
|
|
if (badstream(stream,0)) return;
|
|
if (!cmd->args) stream=-stream;
|
|
|
|
s=push();
|
|
s->type=stNUMBER;
|
|
s->value=oldstream;
|
|
if (infolevel>=DEBUG) {
|
|
sprintf(string,"pushing %d on stack, switching to %d",oldstream,stream);
|
|
error(DEBUG,string);
|
|
}
|
|
oldstream=stream;
|
|
myswitch(stream);
|
|
}
|
|
|
|
|
|
void pop_switch(void) /* pop current stream from stack and switch to it */
|
|
{
|
|
int stream;
|
|
|
|
stream=(int)pop(stNUMBER)->value;
|
|
if (infolevel>=DEBUG) {
|
|
sprintf(string,"popping %d from stack, switching to it",stream);
|
|
error(DEBUG,string);
|
|
}
|
|
myswitch(stream);
|
|
}
|
|
|
|
|
|
void myswitch(int stream) /* switch to specified stream */
|
|
{
|
|
int stdio,input;
|
|
|
|
stdio=(abs(stream)==STDIO_STREAM);
|
|
input=(stream>0);
|
|
currstr=stream;
|
|
if (stream<0) stream=-stream;
|
|
if (badstream(stream,0)) return;
|
|
|
|
if (stdio) {
|
|
cinstr=stdin;
|
|
coutstr=stdout;
|
|
} else {
|
|
cinstr=coutstr=NULL;
|
|
if (input)
|
|
cinstr=streams[stream];
|
|
else
|
|
coutstr=streams[stream];
|
|
}
|
|
}
|
|
|
|
|
|
int checkstream(void) /* test if currst is still valid */
|
|
{
|
|
int stdio,input;
|
|
|
|
stdio=(abs(currstr)==STDIO_STREAM);
|
|
input=(currstr>0);
|
|
|
|
if (!stdio) {
|
|
if (input && !(stream_modes[abs(currstr)] & smREAD| smREADWRITE)) {
|
|
sprintf(string,"stream %d not open for reading",abs(currstr));
|
|
error(ERROR,string);
|
|
return FALSE;
|
|
}
|
|
if (!input && !(stream_modes[abs(currstr)] & (smWRITE | smPRINT))) {
|
|
sprintf(string,"stream %d not open for writing or printing",abs(currstr));
|
|
error(ERROR,string);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void testeof(struct command *cmd) /* close the specified stream */
|
|
{
|
|
int s,c;
|
|
struct stackentry *result;
|
|
|
|
s=(int)pop(stNUMBER)->value;
|
|
if (s!=STDIO_STREAM && badstream(s,0)) return;
|
|
result=push();
|
|
result->type=stNUMBER;
|
|
if (s && !(stream_modes[s] & smREAD)) {
|
|
result->value=1.;
|
|
return;
|
|
}
|
|
if (!s) {
|
|
result->value=0.;
|
|
return;
|
|
}
|
|
c=getc(streams[s]);
|
|
if (c==EOF) {
|
|
result->value=1.;
|
|
return;
|
|
}
|
|
|
|
result->value=0.;
|
|
ungetc(c,streams[s]);
|
|
return;
|
|
}
|
|
|
|
|
|
int badstream(int stream,int errcode) /* test for valid stream id */
|
|
{
|
|
if (stream!=STDIO_STREAM && (stream>FOPEN_MAX-4 || stream<=0)) {
|
|
sprintf(errcode?errorstring:string,"invalid stream: %d (can handle only streams from 1 to %d)",stream,FOPEN_MAX-4);
|
|
if (errcode)
|
|
errorcode=errcode;
|
|
else
|
|
error(ERROR,string);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void create_myread(char type,int tileol) /* create command 'read' */
|
|
{
|
|
struct command *cmd;
|
|
|
|
cmd=add_command(cREAD,NULL);
|
|
cmd->args=tileol; /* true, if read should go til eol */
|
|
cmd->tag=type; /* can be 'd' or 's' */
|
|
}
|
|
|
|
|
|
void myread(struct command *cmd) /* read string or double */
|
|
{
|
|
double d;
|
|
static char buffer[INBUFFLEN]; /* buffer with current input */
|
|
int numread; /* number of bytes read */
|
|
int tileol; /* true, if read should go til end of line */
|
|
struct stackentry *s;
|
|
int currch; /* current character */
|
|
|
|
numread=0; /* no chars read'til now */
|
|
buffer[0]='\0';
|
|
tileol=cmd->args;
|
|
|
|
/* skip leading whitespace */
|
|
if (!tileol) {
|
|
do {
|
|
currch=onechar();
|
|
} while(currch==' ' || currch=='\t');
|
|
/* put back last char */
|
|
if (currch!=EOF && currch!='\0') backchar(currch);
|
|
if (currch=='\0' || currch==EOF) goto done;
|
|
}
|
|
|
|
/* read chars */
|
|
do {
|
|
currch=onechar();
|
|
buffer[numread]=currch;
|
|
numread++;
|
|
} while(((tileol && currch!='\0') ||
|
|
(!tileol && currch!=' ' &&
|
|
currch!='\t' && currch!='\0')) &&
|
|
currch!=EOF && numread<INBUFFLEN);
|
|
|
|
/* put back last char */
|
|
if (currch!=EOF && currch!='\0') backchar(currch);
|
|
/* and remove it from buff */
|
|
if (currch!=EOF) numread--;
|
|
buffer[numread]='\0';
|
|
if (currch=='\0' || currch==EOF) goto done;
|
|
|
|
/* skip trailing whitespace */
|
|
if (!tileol) {
|
|
do {
|
|
currch=onechar();
|
|
} while(currch==' ' || currch=='\t');
|
|
if (currch!=EOF && currch!='\0') backchar(currch);
|
|
}
|
|
|
|
done:
|
|
if (cmd->tag=='s') { /* read string */
|
|
s=push();
|
|
s->type=stSTRING;
|
|
s->pointer=my_strdup(buffer);}
|
|
else { /* read double */
|
|
s=push();
|
|
s->type=stNUMBER;
|
|
s->value=0.0;
|
|
if (buffer[0] && (sscanf(buffer,"%lf",&d)==1)) s->value=d;
|
|
}
|
|
}
|
|
|
|
|
|
static void readline(void) /* read one line from current stream */
|
|
{
|
|
#ifdef UNIX
|
|
char *nl; /* position of newline */
|
|
int x,y;
|
|
#else
|
|
int read;
|
|
#endif
|
|
|
|
if (!checkstream()) return;
|
|
linebuffer[0]='\0';
|
|
#ifdef UNIX
|
|
if (curinized && cinstr==stdin) {
|
|
;
|
|
#ifdef BUILD_NCURSES
|
|
getyx(stdscr,y,x);
|
|
#ifdef HAVE_GETNSTR
|
|
getnstr(linebuffer,INBUFFLEN);
|
|
#else
|
|
getstr(linebuffer);
|
|
#endif
|
|
if ((nl=strchr(linebuffer,'\0'))) {
|
|
*nl='\n';
|
|
*(nl+1)='\0';
|
|
}
|
|
if (y>=LINES-1) scrl(1);
|
|
refresh();
|
|
#endif
|
|
}
|
|
#else
|
|
if (curinized && cinstr==stdin) {
|
|
;
|
|
#ifdef BUILD_NCURSES
|
|
FlushConsoleInputBuffer(ConsoleInput);
|
|
ReadConsole(ConsoleInput,linebuffer,INBUFFLEN,&read,NULL);
|
|
if (read>=2) {
|
|
linebuffer[read-2]='\n';
|
|
linebuffer[read-1]='\0';
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
else {
|
|
fgets(linebuffer,INBUFFLEN,cinstr);
|
|
}
|
|
currchar=linebuffer;
|
|
prompted=FALSE;
|
|
}
|
|
|
|
|
|
static int onechar() /* read one char from cinstr */
|
|
{
|
|
int ch;
|
|
|
|
if (!checkstream()) return '\0';
|
|
if (cinstr==stdin) {
|
|
if (!currchar || !*currchar) {
|
|
readline();
|
|
}
|
|
do {
|
|
ch=*currchar;
|
|
currchar++;
|
|
} while(! (!iscntrl(ch) || strchr(" \t\n",ch) || read_controls || ch=='\0'));
|
|
} else {
|
|
do {
|
|
ch=fgetc(cinstr);
|
|
} while(! (!iscntrl(ch) || strchr(" \t\n",ch) || read_controls || ch=='\0' || ch==EOF));
|
|
}
|
|
|
|
if (ch=='\n' || ch==EOF)
|
|
return '\0';
|
|
else
|
|
return ch;
|
|
}
|
|
|
|
|
|
static void backchar(int ch) /* put char back into stream */
|
|
{
|
|
if (!checkstream()) return;
|
|
if (cinstr==stdin) {
|
|
if (currchar>linebuffer) currchar--;
|
|
}
|
|
else {
|
|
ungetc(ch,cinstr);
|
|
}
|
|
}
|
|
|
|
|
|
void chkprompt() /* print an intermediate prompt if necessary */
|
|
{
|
|
if (cinstr==stdin && (!currchar || !*currchar) && !prompted) onestring("?");
|
|
}
|
|
|
|
|
|
void create_onestring(char *str) /* create command 'onestring' */
|
|
{
|
|
struct command *cmd;
|
|
|
|
cmd=add_command(cONESTRING,NULL);
|
|
cmd->pointer=my_strdup(str);
|
|
}
|
|
|
|
|
|
void onestring(char *s) /* write string to file */
|
|
{
|
|
#ifdef WINDOWS
|
|
DWORD len,written;
|
|
#endif
|
|
|
|
if (!checkstream()) return;
|
|
if (curinized && abs(currstr)==STDIO_STREAM) {
|
|
;
|
|
#ifdef BUILD_NCURSES
|
|
#ifdef UNIX
|
|
addstr(s);
|
|
refresh();
|
|
#else
|
|
len=strlen(s);
|
|
WriteConsole(ConsoleOutput,s,len,&written,NULL);
|
|
#endif
|
|
#endif
|
|
} else if (abs(currstr)==lprstream) {
|
|
#ifdef UNIX
|
|
fprintf(lineprinter,"%s",s);
|
|
fflush(lineprinter);
|
|
#else
|
|
len=strlen(s);
|
|
WritePrinter(lineprinter,s,len,&written);
|
|
#endif
|
|
} else {
|
|
fprintf(coutstr,"%s",s);
|
|
fflush(coutstr);
|
|
}
|
|
prompted=TRUE;
|
|
}
|
|
|
|
|
|
void create_colour(int flag) /* create command 'colour' */
|
|
{
|
|
struct command *c;
|
|
|
|
c=add_command(cCOLOUR,NULL);
|
|
c->args=flag;
|
|
}
|
|
|
|
|
|
void colour(struct command *cmd) /* switch on colour */
|
|
{
|
|
char *fore=NULL,*back=NULL,*p;
|
|
int fc,bc;
|
|
|
|
if (cmd->args && !curinized) {
|
|
error(ERROR,"need to call 'clear screen' first");
|
|
return;
|
|
}
|
|
if (cmd->args==0) {
|
|
if (!curinized) return;
|
|
#ifdef UNIX
|
|
;
|
|
#ifdef BUILD_NCURSES
|
|
if (has_colors())
|
|
attrset(A_NORMAL|COLOR_PAIR(stdfc*8+stdbc));
|
|
else
|
|
attrset(A_NORMAL);
|
|
return;
|
|
#endif
|
|
#else
|
|
SetConsoleTextAttribute(ConsoleOutput,FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
|
|
return;
|
|
#endif
|
|
} else if (cmd->args==1) {
|
|
#ifdef UNIX
|
|
;
|
|
#ifdef BUILD_NCURSES
|
|
if (has_colors())
|
|
attrset(A_NORMAL|COLOR_PAIR(stdbc*8+stdfc));
|
|
else {
|
|
attrset(A_REVERSE);
|
|
return;
|
|
}
|
|
#endif
|
|
#else
|
|
SetConsoleTextAttribute(ConsoleOutput,BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE);
|
|
return;
|
|
#endif
|
|
} else { /* decode colours */
|
|
#ifdef UNIX
|
|
;
|
|
#ifdef BUILD_NCURSES
|
|
if (!has_colors()) {
|
|
pop(stSTRING);
|
|
if (cmd->args==3) pop(stSTRING);
|
|
attrset(A_REVERSE);
|
|
return;
|
|
}
|
|
#endif
|
|
#endif
|
|
if (cmd->args==2) {
|
|
back=NULL;
|
|
fore=pop(stSTRING)->pointer;
|
|
for(p=fore;*p;p++) *p=tolower(*p);
|
|
} else {
|
|
back=pop(stSTRING)->pointer;
|
|
for(p=back;*p;p++) *p=tolower(*p);
|
|
fore=pop(stSTRING)->pointer;
|
|
for(p=fore;*p;p++) *p=tolower(*p);
|
|
}
|
|
fc=name2yc(fore);
|
|
if (fc<0) {
|
|
sprintf(string,"unknown foreground colour: '%s'",fore);
|
|
error(ERROR,string);
|
|
}
|
|
bc=stdbc;
|
|
if (back) {
|
|
bc=name2yc(back);
|
|
if (fc<0) {
|
|
sprintf(string,"unknown background colour: '%s'",back);
|
|
error(ERROR,string);
|
|
}
|
|
}
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
attrset(COLOR_PAIR(fc*8+bc));
|
|
#endif
|
|
#else
|
|
SetConsoleTextAttribute(ConsoleOutput,(WORD)(yc2oc(fc,TRUE)|yc2oc(bc,FALSE)));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
static void initcol(void) /* initialize curses colors */
|
|
{
|
|
static int first=TRUE;
|
|
#ifdef UNIX
|
|
int i,j,col;
|
|
short f,b;
|
|
#else
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
#endif
|
|
|
|
if (!first) return;
|
|
first=FALSE;
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
if (!has_colors()) return;
|
|
start_color();
|
|
|
|
for(i=0;i<8;i++) {
|
|
for(j=0;j<8;j++) {
|
|
if (!i && !j) continue;
|
|
init_pair(i*8+j,yc2oc(i,TRUE),yc2oc(j,FALSE));
|
|
}
|
|
}
|
|
init_color(COLOR_YELLOW,1000,1000,0);
|
|
|
|
col=inch()&A_COLOR;
|
|
pair_content(col,&f,&b);
|
|
stdfc=oc2yc(f);
|
|
stdbc=oc2yc(b);
|
|
bkgdset(COLOR_PAIR(stdfc*8+stdbc));
|
|
#endif
|
|
#else
|
|
GetConsoleScreenBufferInfo(ConsoleOutput,&csbi);
|
|
stdfc=csbi.wAttributes & (FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED);
|
|
stdbc=csbi.wAttributes & (BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_RED);
|
|
#endif
|
|
}
|
|
|
|
|
|
int name2yc(char *name) /* convert a color name to an integer */
|
|
{
|
|
char *c;
|
|
|
|
for(c=name;*c;c++) *c=tolower(*c);
|
|
if (!strcmp(name,"black") || !strcmp(name,"bla")) return YC_BLACK;
|
|
if (!strcmp(name,"white") || !strcmp(name,"whi")) return YC_WHITE;
|
|
if (!strcmp(name,"red") || !strcmp(name,"red")) return YC_RED;
|
|
if (!strcmp(name,"blue") || !strcmp(name,"blu")) return YC_BLUE;
|
|
if (!strcmp(name,"green") || !strcmp(name,"gre")) return YC_GREEN;
|
|
if (!strcmp(name,"yellow") || !strcmp(name,"yel")) return YC_YELLOW;
|
|
if (!strcmp(name,"cyan") || !strcmp(name,"cya")) return YC_CYAN;
|
|
if (!strcmp(name,"magenta") || !strcmp(name,"mag")) return YC_MAGENTA;
|
|
return -1;
|
|
}
|
|
|
|
|
|
int yc2oc(int yc,int fore) /* convert a yabasic color to operating system color */
|
|
{
|
|
#ifdef UNIX
|
|
fore=0; /* stop gcc from complaining */
|
|
if (yc==YC_BLACK) return COLOR_BLACK;
|
|
if (yc==YC_WHITE) return COLOR_WHITE;
|
|
if (yc==YC_RED) return COLOR_RED;
|
|
if (yc==YC_BLUE) return COLOR_BLUE;
|
|
if (yc==YC_GREEN) return COLOR_GREEN;
|
|
if (yc==YC_YELLOW) return COLOR_YELLOW;
|
|
if (yc==YC_CYAN) return COLOR_CYAN;
|
|
if (yc==YC_MAGENTA) return COLOR_MAGENTA;
|
|
#else
|
|
if (fore) {
|
|
if (yc==YC_BLACK) return 0;
|
|
if (yc==YC_WHITE) return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
|
if (yc==YC_RED) return FOREGROUND_RED;
|
|
if (yc==YC_BLUE) return FOREGROUND_BLUE;
|
|
if (yc==YC_GREEN) return FOREGROUND_GREEN;
|
|
if (yc==YC_YELLOW) return FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
|
if (yc==YC_CYAN) return FOREGROUND_GREEN | FOREGROUND_BLUE;
|
|
if (yc==YC_MAGENTA) return FOREGROUND_BLUE | FOREGROUND_RED;
|
|
} else {
|
|
if (yc==YC_BLACK) return 0;
|
|
if (yc==YC_WHITE) return BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
|
|
if (yc==YC_RED) return BACKGROUND_RED;
|
|
if (yc==YC_BLUE) return BACKGROUND_BLUE;
|
|
if (yc==YC_GREEN) return BACKGROUND_GREEN;
|
|
if (yc==YC_YELLOW) return BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
|
|
if (yc==YC_CYAN) return BACKGROUND_GREEN | BACKGROUND_BLUE;
|
|
if (yc==YC_MAGENTA) return BACKGROUND_BLUE | BACKGROUND_RED;
|
|
}
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
|
|
int oc2yc(int oc) /* convert an operating system color to yabasic color */
|
|
{
|
|
#ifdef UNIX
|
|
if (oc==COLOR_BLACK) return YC_BLACK;
|
|
if (oc==COLOR_WHITE) return YC_WHITE;
|
|
if (oc==COLOR_RED) return YC_RED;
|
|
if (oc==COLOR_BLUE) return YC_BLUE;
|
|
if (oc==COLOR_GREEN) return YC_GREEN;
|
|
if (oc==COLOR_YELLOW) return YC_YELLOW;
|
|
if (oc==COLOR_CYAN) return YC_CYAN;
|
|
if (oc==COLOR_MAGENTA) return YC_MAGENTA;
|
|
#else
|
|
if (oc==0) return YC_BLACK;
|
|
if (oc==(FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN) ||
|
|
oc==(BACKGROUND_RED|BACKGROUND_BLUE|BACKGROUND_GREEN)) return YC_WHITE;
|
|
if (oc==(FOREGROUND_RED) ||
|
|
oc==(BACKGROUND_RED)) return YC_RED;
|
|
if (oc==(FOREGROUND_BLUE) ||
|
|
oc==(BACKGROUND_BLUE)) return YC_BLUE;
|
|
if (oc==(FOREGROUND_GREEN) ||
|
|
oc==(BACKGROUND_GREEN)) return YC_GREEN;
|
|
if (oc==(FOREGROUND_RED|FOREGROUND_GREEN) ||
|
|
oc==(BACKGROUND_RED|BACKGROUND_GREEN) ||
|
|
oc==(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY) ||
|
|
oc==(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_INTENSITY)) return YC_YELLOW;
|
|
if (oc==(FOREGROUND_BLUE|FOREGROUND_GREEN) ||
|
|
oc==(BACKGROUND_BLUE|BACKGROUND_GREEN)) return YC_CYAN;
|
|
if (oc==(FOREGROUND_RED|FOREGROUND_BLUE) ||
|
|
oc==(BACKGROUND_RED|BACKGROUND_BLUE)) return YC_MAGENTA;
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
|
|
void putchars(void) /* put rect onto screen */
|
|
{
|
|
char *ch,text,fore[4],back[4];
|
|
int n,sx,sy,x,y,f,b;
|
|
int tox,toy;
|
|
int oldx,oldy;
|
|
#ifdef WINDOWS
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
COORD cp;
|
|
char buff[2];
|
|
int written;
|
|
#endif
|
|
|
|
toy=(int)(pop(stNUMBER)->value);
|
|
tox=(int)(pop(stNUMBER)->value);
|
|
ch=pop(stSTRING)->pointer;
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
getyx(stdscr,oldy,oldx);
|
|
#endif
|
|
#else
|
|
GetConsoleScreenBufferInfo(ConsoleOutput,&csbi);
|
|
oldx=csbi.dwCursorPosition.X;
|
|
oldy=csbi.dwCursorPosition.Y;
|
|
#endif
|
|
if (sscanf(ch,"%d,%d:%n",&sx,&sy,&n)!=2) {
|
|
error(ERROR,"illegal screen string");
|
|
return;
|
|
}
|
|
ch+=n;
|
|
for(x=tox;x<tox+sx;x++) {
|
|
if (x<0 || x>=COLS) continue;
|
|
for(y=toy;y<toy+sy;y++) {
|
|
if (x<0 || x>=COLS || y<0 || y>=LINES) {
|
|
for(n=0;n<10;n++) if (*ch) ch++;
|
|
continue;
|
|
}
|
|
if (!*ch) {
|
|
text=' ';
|
|
f=YC_BLACK;
|
|
b=YC_BLACK;
|
|
} else {
|
|
text=*ch;
|
|
strncpy(fore,ch+2,3);
|
|
fore[3]='\0';
|
|
strncpy(back,ch+6,3);
|
|
back[3]='\0';
|
|
for(n=0;n<10;n++) if (*ch) ch++;
|
|
f=name2yc(fore);
|
|
if (f<0) f=YC_WHITE;
|
|
b=name2yc(back);
|
|
if (b<0) b=YC_WHITE;
|
|
}
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
if (has_colors()) attrset(COLOR_PAIR(f*8+b));
|
|
mvaddch(y,x,text);
|
|
#endif
|
|
#else
|
|
cp.X=x;
|
|
cp.Y=y;
|
|
SetConsoleCursorPosition(ConsoleOutput,cp);
|
|
SetConsoleTextAttribute(ConsoleOutput,(WORD)(yc2oc(f,TRUE)|yc2oc(b,FALSE)));
|
|
buff[0]=text;
|
|
buff[1]='\0';
|
|
WriteConsole(ConsoleOutput,buff,1,&written,NULL);
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
if (has_colors())
|
|
attrset(A_NORMAL|COLOR_PAIR(stdfc*8+stdbc));
|
|
else
|
|
attrset(A_NORMAL);
|
|
move(y,x);
|
|
refresh();
|
|
#endif
|
|
#else
|
|
cp.X=oldx;
|
|
cp.Y=oldy;
|
|
SetConsoleCursorPosition(ConsoleOutput,cp);
|
|
SetConsoleTextAttribute(ConsoleOutput,(WORD)(stdfc|stdbc));
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
char *getchars(int xf,int yf,int xt,int yt) /* get rect from screen */
|
|
{
|
|
int x,y;
|
|
#ifdef UNIX
|
|
int c,ct,cc;
|
|
#endif
|
|
int cf,cb;
|
|
int oldx,oldy;
|
|
char *res;
|
|
char cols[20];
|
|
#ifdef WINDOWS
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
COORD cp;
|
|
char charbuff[2];
|
|
WORD attrbuff[2];
|
|
int read;
|
|
#endif
|
|
|
|
if (xf>xt) {x=xf;xf=xt;xt=x;}
|
|
if (yf>yt) {y=yf;yf=yt;yt=y;}
|
|
|
|
res=my_malloc(12+(xt-xf+1)*(yt-yf+1)*12);
|
|
sprintf(res,"%d,%d:",xt-xf+1,yt-yf+1);
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
getyx(stdscr,oldy,oldx);
|
|
#endif
|
|
#else
|
|
GetConsoleScreenBufferInfo(ConsoleOutput,&csbi);
|
|
oldx=csbi.dwCursorPosition.X;
|
|
oldy=csbi.dwCursorPosition.Y;
|
|
#endif
|
|
|
|
for(x=xf;x<=xt;x++) {
|
|
for(y=yf;y<=yt;y++) {
|
|
if (y<0 || y>=LINES || x<0 || x>=COLS) {
|
|
strcat(res," blbl");
|
|
} else {
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
c=mvinch(y,x);
|
|
ct=c&A_CHARTEXT;
|
|
if (!isprint(ct)) ct=' ';
|
|
cc=PAIR_NUMBER(c&A_COLOR);
|
|
cb=cc&7;
|
|
cf=(cc-cb)/8;
|
|
if (has_colors()) {
|
|
sprintf(cols,"%c:%s:%s,",ct,yc2short(cf),yc2short(cb));
|
|
} else
|
|
{
|
|
|
|
sprintf(cols,"%c:???:???,",ct);
|
|
}
|
|
#endif
|
|
#else
|
|
cp.X=x;
|
|
cp.Y=y;
|
|
ReadConsoleOutputCharacter(ConsoleOutput,charbuff,1,cp,&read);
|
|
charbuff[1]='\0';
|
|
ReadConsoleOutputAttribute(ConsoleOutput,attrbuff,1,cp,&read);
|
|
cf=oc2yc(attrbuff[0]&(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE));
|
|
cb=oc2yc(attrbuff[0]&(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE));
|
|
sprintf(cols,"%c:%s:%s,",charbuff[0],yc2short(cf),yc2short(cb));
|
|
#endif
|
|
strcat(res,cols);
|
|
}
|
|
}
|
|
}
|
|
#ifdef UNIX
|
|
#ifdef BUILD_NCURSES
|
|
move(oldy,oldx);
|
|
#endif
|
|
#endif
|
|
res[strlen(res)-1]='\0';
|
|
return res;
|
|
}
|
|
|
|
|
|
char *yc2short(int col) /* convert yabasic colours to short colour name */
|
|
{
|
|
static char r1[4],r2[4];
|
|
static char *pr=r1;
|
|
|
|
if (pr==r1)
|
|
pr=r2;
|
|
else
|
|
pr=r1;
|
|
|
|
strcpy(pr,"***");
|
|
if (col==YC_BLACK) strcpy(pr,"Bla");
|
|
if (col==YC_WHITE) strcpy(pr,"Whi");
|
|
if (col==YC_RED) strcpy(pr,"Red");
|
|
if (col==YC_BLUE) strcpy(pr,"Blu");
|
|
if (col==YC_GREEN) strcpy(pr,"Gre");
|
|
if (col==YC_YELLOW) strcpy(pr,"Yel");
|
|
if (col==YC_CYAN) strcpy(pr,"Cya");
|
|
if (col==YC_MAGENTA) strcpy(pr,"Mag");
|
|
|
|
return pr;
|
|
}
|
|
|