Added Blocks
This commit is contained in:
parent
31098a6e6b
commit
40ad25b725
BIN
Blocks/BLOCKS.COM
Normal file
BIN
Blocks/BLOCKS.COM
Normal file
Binary file not shown.
BIN
Blocks/CC.COM
Normal file
BIN
Blocks/CC.COM
Normal file
Binary file not shown.
BIN
Blocks/CCOPT.COM
Normal file
BIN
Blocks/CCOPT.COM
Normal file
Binary file not shown.
BIN
Blocks/HEXTOCOM.COM
Normal file
BIN
Blocks/HEXTOCOM.COM
Normal file
Binary file not shown.
34
Blocks/README.md
Normal file
34
Blocks/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Blocks
|
||||
|
||||
This is a clon (more or less) of SameGame, a tile-matching puzzle video game, originally released under the name Chain Shot! in 1985 by Kuniaki Moribe (Morisuke).
|
||||
|
||||
The goal of the game is to remove all the blocks of the board.
|
||||
|
||||
Copyright (c) 1999-2018 Miguel García / FloppySoftware
|
||||
|
||||
The file ``kslib.h`` has been modified for VT100 compatibility (insted of VT52) by me (Anna Christina Naß <acn@acn.wtf>.
|
||||
|
||||
Original Repository: https://github.com/MiguelVis/RetroProjects
|
||||
Website: http://www.floppysoftware.es/blocks.html?path=cpm_projects|blocks
|
||||
|
||||
The file ``BLOCKS.COM`` is the compiled game file.
|
||||
|
||||
## Commands
|
||||
|
||||
Move the cursor using Q, O, P and A as shown on the screen.
|
||||
|
||||
## Compile:
|
||||
|
||||
To compile, use MESCC, "Mike's Enhanced Small C Compiler".
|
||||
See: http://www.floppysoftware.es/mescc.html?path=cpm_projects|mescc
|
||||
|
||||
I provide the files neccessary to compile Blocks, using:
|
||||
|
||||
CC BLOCKS
|
||||
CCOPT BLOCKS
|
||||
ZSM BLOCKS
|
||||
HEXTOCOM BLOCKS
|
||||
|
||||
## License:
|
||||
|
||||
GPL Version 2, see copying.txt - valid for MESCC and Blocks.
|
BIN
Blocks/ZSM.COM
Normal file
BIN
Blocks/ZSM.COM
Normal file
Binary file not shown.
866
Blocks/blocks.c
Normal file
866
Blocks/blocks.c
Normal file
@ -0,0 +1,866 @@
|
||||
/* BLOCKS!
|
||||
|
||||
Game from Floppy Software for MESCC - Mike's Enhanced Small C Compiler.
|
||||
|
||||
Copyright (c) 2012 Miguel I. Garcia Lopez, Valencia, Spain.
|
||||
|
||||
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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Revisions:
|
||||
|
||||
02 Jul 2012 : Generic CP/M version 1.0 for 24x80 VT52 screen.
|
||||
*/
|
||||
|
||||
#include <mescc.h> /* MESCC header & runtime */
|
||||
#include <string.h> /* We need strlen() */
|
||||
#include <ctype.h> /* We need toupper() */
|
||||
#include <sprintf.h> /* We need sprintf() */
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef WORD
|
||||
#define WORD unsigned int
|
||||
#endif
|
||||
|
||||
#include <kslib.h> /* Screen output for CP/M */
|
||||
#include <kslibfun.h> /* More functions for kslib */
|
||||
|
||||
/* GAME DEFS
|
||||
*/
|
||||
|
||||
#define BOARD_ROW 6 /* Screen position for board */
|
||||
#define BOARD_COL 25 /* id */
|
||||
|
||||
#define BORDER_ROW 5 /* Screen position for border */
|
||||
#define BORDER_COL 24 /* id */
|
||||
|
||||
#define BOARD_ROWS 10 /* Board rows */
|
||||
#define BOARD_COLS 10 /* Board columns */
|
||||
|
||||
#define BLOCK_COLS 3 /* Block size */
|
||||
#define BLOCK_ROWS 1 /* id */
|
||||
|
||||
#define BLOCK_EMPTY ' ' /* Value if block is empty */
|
||||
|
||||
#define LEVEL_ROW 2 /* Screen position for level info - used to show blocks killed */
|
||||
#define LEVEL_COL 2 /* id */
|
||||
|
||||
#define SCORE_ROW 2 /* Screen position for score info */
|
||||
#define SCORE_COL 73 /* id */
|
||||
|
||||
#define K_UP 'Q' /* Key up */
|
||||
#define K_DOWN 'A' /* Key down */
|
||||
#define K_LEFT 'O' /* Key left */
|
||||
#define K_RIGHT 'P' /* Key right */
|
||||
#define K_EXIT 'X' /* Key exit */
|
||||
#define K_SELECT 'S' /* Key select */
|
||||
#define K_KILL 'K' /* Key kill */
|
||||
#define K_GRAV_UP '1' /* Key gravity up */
|
||||
#define K_GRAV_LEFT '2' /* Key gravity left */
|
||||
#define K_GRAV_RIGHT '3' /* Key gravity right */
|
||||
#define K_GRAV_DOWN '4' /* Key gravity down */
|
||||
|
||||
/* VARIABLES
|
||||
*/
|
||||
|
||||
WORD board[BOARD_ROWS]; /* Array for blocks values <<char *board[] -- MESCC things>> */
|
||||
WORD board_sel[BOARD_ROWS]; /* Array for blocks selections <<id>> */
|
||||
|
||||
int score, /* Score */
|
||||
blocks, /* Blocks remaining */
|
||||
randindex, /* Random number used for generate blocks values */
|
||||
selected, /* Number of blocks selected */
|
||||
add_to_score, /* How much can I add to score if I kill selected blocks */
|
||||
automode, /* Non zero if automode is selected */
|
||||
ChkPlsCtr, /* CheckPlease variable */
|
||||
ChkPlsMul, /* id */
|
||||
ChkPlsVal; /* id */
|
||||
|
||||
/* MAIN FUNCTION
|
||||
*/
|
||||
|
||||
main(argc, argv)
|
||||
int argc, argv[];
|
||||
{
|
||||
int opt;
|
||||
|
||||
/* SETUP KSLIB ENVIRONMENT
|
||||
*/
|
||||
|
||||
KbdScrStart();
|
||||
|
||||
/* SETUP SOME THINGS
|
||||
*/
|
||||
|
||||
board[0]="1234567890"; board_sel[0]="1234567890";
|
||||
board[1]="1234567890"; board_sel[1]="1234567890";
|
||||
board[2]="1234567890"; board_sel[2]="1234567890";
|
||||
board[3]="1234567890"; board_sel[3]="1234567890";
|
||||
board[4]="1234567890"; board_sel[4]="1234567890";
|
||||
board[5]="1234567890"; board_sel[5]="1234567890";
|
||||
board[6]="1234567890"; board_sel[6]="1234567890";
|
||||
board[7]="1234567890"; board_sel[7]="1234567890";
|
||||
board[8]="1234567890"; board_sel[8]="1234567890";
|
||||
board[9]="1234567890"; board_sel[9]="1234567890";
|
||||
|
||||
/* PLAY THE GAME, PLEASE
|
||||
*/
|
||||
|
||||
while((opt=Menu()))
|
||||
{
|
||||
if(opt==1)
|
||||
Play();
|
||||
}
|
||||
|
||||
/* GAME IS OVER - BEST TO CLEAN THE SCREEN
|
||||
*/
|
||||
|
||||
ScrClr(); ScrCurOn();
|
||||
|
||||
/* WE SAY GOOD BYE TO KSLIB ENVIRONMENT & WE SAY HELLO TO CP/M
|
||||
*/
|
||||
|
||||
KbdScrEnd();
|
||||
}
|
||||
|
||||
/* MENU - RETURN 0 IF WE WANT TO END GAME, 1 IF WE WANT TO PLAY GAME, OR 2 IF WE WANT TO RETURN TO MENU
|
||||
*/
|
||||
|
||||
Menu()
|
||||
{
|
||||
ScrClr(); ScrCurOff();
|
||||
|
||||
ScrTitle(0, "BLOCKS");
|
||||
ScrTitle(1, "v1.0");
|
||||
ScrTitle(3, "(c) 2012 FLOPPY SOFTWARE");
|
||||
|
||||
ScrOutStrRC( 6, 25, "1 : PLAY GAME IN NORMAL MODE");
|
||||
ScrOutStrRC( 8, 25, "2 : PLAY GAME IN AUTOMATIC MODE");
|
||||
ScrOutStrRC(10, 25, "3 : SHOW HELP");
|
||||
|
||||
ScrOutStrRC(12, 25, "X : EXIT GAME");
|
||||
|
||||
ScrTitle(SCR_ROWS-2, "SELECT YOUR CHOICE");
|
||||
|
||||
randindex=0; /* This is used to generate a random number */
|
||||
|
||||
while(1)
|
||||
{
|
||||
while(!KbdChk())
|
||||
{
|
||||
if(++randindex==BOARD_ROWS*BOARD_COLS)
|
||||
randindex=0;
|
||||
}
|
||||
|
||||
switch(toupper(KbdIn()))
|
||||
{
|
||||
case '1' : automode=0; return 1;
|
||||
case '2' : automode=1; return 1;
|
||||
case '3' : Help(); return 2;
|
||||
case 'X' : return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* HELP -- SHOW HELP
|
||||
*/
|
||||
|
||||
Help()
|
||||
{
|
||||
ScrClr();
|
||||
|
||||
ScrTitle( 0, "BLOCKS");
|
||||
|
||||
ScrTitle( 2, "The object of the game is to remove all the");
|
||||
ScrTitle( 3, "blocks of the board.");
|
||||
ScrTitle( 5, "You can select just one block, or a group of");
|
||||
ScrTitle( 6, "blocks of the same type.");
|
||||
ScrTitle( 8, "Then, if you are in the normal mode, you can place all");
|
||||
ScrTitle( 9, "the blocks against a side (top, bottom, left or right).");
|
||||
ScrTitle(11, "If you are in the automatic mode, the blocks rows will be");
|
||||
ScrTitle(12, "placed on the bottom side of the board, and the columns");
|
||||
ScrTitle(13, "will be placed on the middle of the board.");
|
||||
ScrTitle(15, "The partial score is the square of the number of");
|
||||
ScrTitle(16, "blocks selected.");
|
||||
ScrTitle(18, "The special block 'X', multiplies that result by 10.");
|
||||
ScrTitle(20, "Good luck!");
|
||||
ScrTitle(22, "PRESS ANY KEY");
|
||||
|
||||
KbdIn();
|
||||
}
|
||||
|
||||
/* PLAY THE GAME, PLEASE
|
||||
*/
|
||||
|
||||
Play()
|
||||
{
|
||||
int row, col, run, val, key;
|
||||
|
||||
/* SETUP VARIABLES & BOARD
|
||||
*/
|
||||
|
||||
row=col=selected=score=0; run=1;
|
||||
|
||||
blocks=BOARD_ROWS*BOARD_COLS;
|
||||
|
||||
SetupBoard();
|
||||
|
||||
/* DRAW SCREEN
|
||||
*/
|
||||
|
||||
ScrClr();
|
||||
|
||||
ScrBox(0, 0, SCR_ROWS-1, SCR_COLS, NULL); ScrTitle(0, "| BLOCKS |");
|
||||
|
||||
ScrOutStrRC(LEVEL_ROW, LEVEL_COL, "BLOCKS"); PrintBlocks();
|
||||
|
||||
ScrOutStrRC(SCORE_ROW, SCORE_COL, "SCORE"); PrintScore();
|
||||
|
||||
|
||||
ScrBox(BORDER_ROW, BORDER_COL, BOARD_ROWS*BLOCK_ROWS+2, BOARD_COLS*BLOCK_COLS+2, NULL);
|
||||
|
||||
|
||||
PaintBoard();
|
||||
|
||||
|
||||
if(!automode)
|
||||
{
|
||||
scrTitle(BORDER_ROW-1, "1");
|
||||
|
||||
ScrTitle(BORDER_ROW+BOARD_ROWS+2, "4");
|
||||
|
||||
ScrOutStrRC(BORDER_ROW+5, BORDER_COL-2, "2");
|
||||
|
||||
ScrOutStrRC(BORDER_ROW+5, BORDER_COL+BOARD_COLS*BLOCK_COLS+3, "3");
|
||||
}
|
||||
|
||||
ScrOutStrRC(BORDER_ROW+3, 7, " Q");
|
||||
ScrOutStrRC(BORDER_ROW+4, 7, " |");
|
||||
ScrOutStrRC(BORDER_ROW+5, 7, "O --x-- P");
|
||||
ScrOutStrRC(BORDER_ROW+6, 7, " |");
|
||||
ScrOutStrRC(BORDER_ROW+7, 7, " A");
|
||||
|
||||
ScrOutStrRC(BORDER_ROW+4, BORDER_COL+BOARD_COLS*BLOCK_COLS+8, "S> SELECT BLOCKS");
|
||||
ScrOutStrRC(BORDER_ROW+5, BORDER_COL+BOARD_COLS*BLOCK_COLS+8, "K> KILL BLOCKS");
|
||||
ScrOutStrRC(BORDER_ROW+6, BORDER_COL+BOARD_COLS*BLOCK_COLS+8, "X> EXIT");
|
||||
|
||||
/* PLAY GAME
|
||||
*/
|
||||
|
||||
while(run)
|
||||
{
|
||||
/* DRAW CURSOR
|
||||
*/
|
||||
|
||||
ScrSetRC(BOARD_ROW+row*BLOCK_ROWS, BOARD_COL+col*BLOCK_COLS+1); ScrCurOn();
|
||||
|
||||
/* USER ACTION
|
||||
*/
|
||||
|
||||
key=toupper(KbdIn());
|
||||
|
||||
ScrCurOff();
|
||||
|
||||
switch(key)
|
||||
{
|
||||
case K_UP: if(row) --row;
|
||||
break;
|
||||
|
||||
case K_DOWN: if(++row==BOARD_ROWS) --row;
|
||||
break;
|
||||
|
||||
case K_LEFT: if(col) --col;
|
||||
break;
|
||||
|
||||
case K_RIGHT: if(++col==BOARD_COLS) -- col;
|
||||
break;
|
||||
|
||||
case K_SELECT: /* CHECK FOR VALID BLOCKS
|
||||
*/
|
||||
|
||||
val=GetBlock(row, col);
|
||||
|
||||
if(val==BLOCK_EMPTY || val=='X')
|
||||
break;
|
||||
|
||||
/* CHECK IF ALREADY SELECTED
|
||||
*/
|
||||
|
||||
if(TstSelBlock(row, col))
|
||||
break;
|
||||
|
||||
/* UNSELECT PREVIOUS SELECTION
|
||||
*/
|
||||
|
||||
if(selected)
|
||||
{
|
||||
/* HEY! TOO MUCH WORK IF ONLY 1 SELECTED */
|
||||
|
||||
UnSelAllBlocks();
|
||||
PaintBoard();
|
||||
}
|
||||
|
||||
/* SELECT
|
||||
*/
|
||||
|
||||
selected=CheckPlease(row, col);
|
||||
|
||||
add_to_score=selected*selected*ChkPlsMul;
|
||||
|
||||
PrintSelec();
|
||||
|
||||
break;
|
||||
|
||||
case K_KILL: if(selected)
|
||||
{
|
||||
/* HEY! TOO MUCH WORK IF ONLY 1 SELECTED */
|
||||
|
||||
KillSelBlocks();
|
||||
|
||||
score+=add_to_score;
|
||||
|
||||
PrintScore();
|
||||
|
||||
blocks-=selected; PrintBlocks();
|
||||
|
||||
selected=add_to_score=0;
|
||||
|
||||
PrintSelec();
|
||||
|
||||
if(!blocks)
|
||||
{
|
||||
GameOver(); run=0;
|
||||
}
|
||||
else if(automode)
|
||||
{
|
||||
DoAutoMode(); PaintBoard();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case K_GRAV_UP: if(automode)
|
||||
break;
|
||||
|
||||
GravityUp();
|
||||
|
||||
if(selected)
|
||||
{
|
||||
UnSelAllBlocks(); selected=0;
|
||||
}
|
||||
|
||||
PaintBoard();
|
||||
|
||||
break;
|
||||
|
||||
case K_GRAV_DOWN:
|
||||
if(automode)
|
||||
break;
|
||||
|
||||
GravityDown();
|
||||
|
||||
if(selected)
|
||||
{
|
||||
UnSelAllBlocks(); selected=0;
|
||||
}
|
||||
|
||||
PaintBoard();
|
||||
|
||||
break;
|
||||
|
||||
case K_GRAV_LEFT:
|
||||
if(automode)
|
||||
break;
|
||||
|
||||
GravityLeft();
|
||||
|
||||
if(selected)
|
||||
{
|
||||
UnSelAllBlocks(); selected=0;
|
||||
}
|
||||
|
||||
PaintBoard();
|
||||
|
||||
break;
|
||||
|
||||
case K_GRAV_RIGHT:
|
||||
if(automode)
|
||||
break;
|
||||
|
||||
GravityRight();
|
||||
|
||||
if(selected)
|
||||
{
|
||||
UnSelAllBlocks(); selected=0;
|
||||
}
|
||||
|
||||
PaintBoard();
|
||||
|
||||
break;
|
||||
|
||||
case K_EXIT :
|
||||
PrintMsg("ARE YOU SURE Y/N?");
|
||||
|
||||
if(toupper(KbdIn())=='Y')
|
||||
run=0;
|
||||
else
|
||||
PrintMsg("");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* GAME IS OVER
|
||||
*/
|
||||
|
||||
GameOver()
|
||||
{
|
||||
ScrTitle(BORDER_ROW+4, "*** GAME OVER ***");
|
||||
|
||||
PrintMsg("PRESS ANY KEY");
|
||||
|
||||
KbdIn();
|
||||
}
|
||||
|
||||
/* SETUP BOARD
|
||||
*/
|
||||
|
||||
SetupBoard()
|
||||
{
|
||||
int r, c; unsigned char *values;
|
||||
|
||||
/* 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 (width 100) */
|
||||
values="4321242333123432411123443444432111234332222343331214422444441243444132222311114242423111133222441111";
|
||||
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
{
|
||||
for(c=0; c!=BOARD_COLS; ++c)
|
||||
{
|
||||
SetBlock(r, c, values[randindex]);
|
||||
|
||||
UnSelBlock(r, c);
|
||||
|
||||
if(++randindex==BOARD_ROWS*BOARD_COLS)
|
||||
randindex=0;
|
||||
}
|
||||
}
|
||||
|
||||
if(randindex<25)
|
||||
SetBlock(2, 5, 'X');
|
||||
else if(randindex<50)
|
||||
SetBlock(9, 4, 'X');
|
||||
else if(randindex<75)
|
||||
SetBlock(4, 8, 'X');
|
||||
else
|
||||
SetBlock(7, 3, 'X');
|
||||
}
|
||||
|
||||
/* SET BLOCK WITH VALUE
|
||||
*/
|
||||
|
||||
SetBlock(row, col, value)
|
||||
int row, col, value;
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr=board[row];
|
||||
|
||||
ptr[col]=value;
|
||||
}
|
||||
|
||||
/* GET BLOCK VALUE
|
||||
*/
|
||||
|
||||
GetBlock(row, col)
|
||||
int row, col;
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr=board[row];
|
||||
|
||||
return ptr[col];
|
||||
}
|
||||
|
||||
/* SELECT BLOCK
|
||||
*/
|
||||
|
||||
SelBlock(row, col)
|
||||
int row, col;
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr=board_sel[row];
|
||||
|
||||
ptr[col]=1;
|
||||
}
|
||||
|
||||
/* UNSELECT BLOCK
|
||||
*/
|
||||
|
||||
UnSelBlock(row, col)
|
||||
int row, col;
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr=board_sel[row];
|
||||
|
||||
ptr[col]=0;
|
||||
}
|
||||
|
||||
/* UNSELECT ALL BLOCKS
|
||||
*/
|
||||
|
||||
UnSelAllBlocks()
|
||||
{
|
||||
int r, c;
|
||||
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
for(c=0; c!=BOARD_COLS; ++c)
|
||||
UnSelBlock(r, c);
|
||||
}
|
||||
|
||||
/* TEST IF A BLOCK IS SELECTED
|
||||
*/
|
||||
|
||||
TstSelBlock(row, col)
|
||||
int row, col;
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr=board_sel[row];
|
||||
|
||||
return ptr[col];
|
||||
}
|
||||
|
||||
/* KILL SELECTED BLOCKS
|
||||
*/
|
||||
|
||||
KillSelBlocks()
|
||||
{
|
||||
int r, c;
|
||||
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
{
|
||||
for(c=0; c!=BOARD_COLS; ++c)
|
||||
{
|
||||
if(TstSelBlock(r, c))
|
||||
{
|
||||
SetBlock(r, c, BLOCK_EMPTY);
|
||||
UnSelBlock(r, c);
|
||||
PaintBlock(r, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PAINT BLOCK
|
||||
*/
|
||||
|
||||
PaintBlock(row, col)
|
||||
int row, col;
|
||||
{
|
||||
int selected;
|
||||
|
||||
ScrSetRC(BOARD_ROW+row*BLOCK_ROWS, BOARD_COL+col*BLOCK_COLS);
|
||||
|
||||
ScrOut((selected=TstSelBlock(row, col)) ? ':' : ' ');
|
||||
|
||||
switch(GetBlock(row, col))
|
||||
{
|
||||
case '1' : ScrOut('$'); break;
|
||||
case '2' : ScrOut('O'); break;
|
||||
case '3' : ScrOut('+'); break;
|
||||
case '4' : ScrOut('#'); break;
|
||||
case 'X' : ScrOut('X'); break;
|
||||
case BLOCK_EMPTY : ScrOut(' '); break;
|
||||
default : ScrOut('?'); break;
|
||||
}
|
||||
|
||||
ScrOut(selected ? ':' : ' ');
|
||||
}
|
||||
|
||||
/* PAINT ALL BLOCKS
|
||||
*/
|
||||
|
||||
PaintBoard()
|
||||
{
|
||||
int r, c;
|
||||
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
for(c=0; c!=BOARD_COLS; ++c)
|
||||
PaintBlock(r, c);
|
||||
}
|
||||
|
||||
/* CHECK WHAT BLOCKS CAN BE SELECTED - SETUP THREE VARIABLES
|
||||
*/
|
||||
|
||||
CheckPlease(row, col)
|
||||
int row, col;
|
||||
{
|
||||
ChkPlsCtr=0; ChkPlsMul=1; ChkPlsVal=GetBlock(row, col);
|
||||
|
||||
ChkPls2(row, col);
|
||||
|
||||
return ChkPlsCtr;
|
||||
}
|
||||
|
||||
ChkPls2(row, col)
|
||||
int row, col;
|
||||
{
|
||||
int val;
|
||||
|
||||
SelBlock(row, col); PaintBlock(row, col);
|
||||
|
||||
if(GetBlock(row, col)=='X')
|
||||
ChkPlsMul=10;
|
||||
|
||||
if(row)
|
||||
{
|
||||
if(((val=GetBlock(row-1, col))==ChkPlsVal || val=='X') && (!TstSelBlock(row-1, col)))
|
||||
ChkPls2(row-1, col);
|
||||
}
|
||||
|
||||
if(col<(BOARD_COLS-1))
|
||||
{
|
||||
if(((val=GetBlock(row, col+1))==ChkPlsVal || val=='X') && (!TstSelBlock(row, col+1)))
|
||||
ChkPls2(row, col+1);
|
||||
}
|
||||
|
||||
if(row<(BOARD_ROWS-1))
|
||||
{
|
||||
if(((val=GetBlock(row+1, col))==ChkPlsVal || val=='X') && (!TstSelBlock(row+1, col)))
|
||||
ChkPls2(row+1, col);
|
||||
}
|
||||
|
||||
if(col)
|
||||
{
|
||||
if(((val=GetBlock(row, col-1))==ChkPlsVal || val=='X') && (!TstSelBlock(row, col-1)))
|
||||
ChkPls2(row, col-1);
|
||||
}
|
||||
|
||||
++ChkPlsCtr;
|
||||
}
|
||||
|
||||
/* GRAVITY DOWN (BOARD BOTTOM)
|
||||
*/
|
||||
|
||||
GravityDown()
|
||||
{
|
||||
int r, c, i, blk, row[BOARD_ROWS];
|
||||
|
||||
for(c=0; c!=BOARD_COLS; ++c)
|
||||
{
|
||||
for((r=i=BOARD_ROWS-1); r!=-1; --r)
|
||||
{
|
||||
if((blk=GetBlock(r, c))!=BLOCK_EMPTY)
|
||||
row[i--]=blk;
|
||||
}
|
||||
|
||||
while(i!=-1)
|
||||
row[i--]=BLOCK_EMPTY;
|
||||
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
SetBlock(r, c, row[r]);
|
||||
}
|
||||
}
|
||||
|
||||
/* GRAVITY UP (WE PUT BLOCKS ON BOARD TOP)
|
||||
*/
|
||||
|
||||
GravityUp()
|
||||
{
|
||||
int r, c, i, blk, row[BOARD_ROWS];
|
||||
|
||||
for(c=0; c!=BOARD_COLS; ++c)
|
||||
{
|
||||
for((r=i=0); r!=BOARD_ROWS; ++r)
|
||||
{
|
||||
if((blk=GetBlock(r, c))!=BLOCK_EMPTY)
|
||||
row[i++]=blk;
|
||||
}
|
||||
|
||||
while(i!=BOARD_ROWS)
|
||||
row[i++]=BLOCK_EMPTY;
|
||||
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
SetBlock(r, c, row[r]);
|
||||
}
|
||||
}
|
||||
|
||||
/* GRAVITY LEFT (WE PUT BLOCKS ON BOARD LEFT)
|
||||
*/
|
||||
|
||||
GravityLeft()
|
||||
{
|
||||
int r, c, i, blk, col[BOARD_ROWS];
|
||||
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
{
|
||||
for((c=i=0); c!=BOARD_COLS; ++c)
|
||||
{
|
||||
if((blk=GetBlock(r, c))!=BLOCK_EMPTY)
|
||||
col[i++]=blk;
|
||||
}
|
||||
|
||||
while(i!=BOARD_COLS)
|
||||
col[i++]=BLOCK_EMPTY;
|
||||
|
||||
for(c=0; c!=BOARD_COLS; ++c)
|
||||
SetBlock(r, c, col[c]);
|
||||
}
|
||||
}
|
||||
|
||||
/* GRAVITY RIGHT (WE PUT BLOCKS ON BOARD RIGHT)
|
||||
*/
|
||||
|
||||
GravityRight()
|
||||
{
|
||||
int r, c, i, blk, col[BOARD_ROWS];
|
||||
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
{
|
||||
for((c=i=BOARD_COLS-1); c!=-1; --c)
|
||||
{
|
||||
if((blk=GetBlock(r, c))!=BLOCK_EMPTY)
|
||||
col[i--]=blk;
|
||||
}
|
||||
|
||||
while(i!=-1)
|
||||
col[i--]=BLOCK_EMPTY;
|
||||
|
||||
for(c=0; c!=BOARD_COLS; ++c)
|
||||
SetBlock(r, c, col[c]);
|
||||
}
|
||||
}
|
||||
|
||||
/* AUTOMATIC MODE (WE PUT BLOKS FIRST ON BOARD BOTTOM, THEN WE CENTER THE COLUMNS)
|
||||
*/
|
||||
|
||||
DoAutoMode()
|
||||
{
|
||||
int r, c, i, pos, cols;
|
||||
|
||||
GravityDown();
|
||||
|
||||
/* COPY NON EMPTY COLUMNS TO THE LEFT
|
||||
*/
|
||||
|
||||
for(i=c=0; c!=BOARD_COLS; ++c)
|
||||
{
|
||||
if(GetBlock(BOARD_ROWS-1, c) != BLOCK_EMPTY)
|
||||
{
|
||||
if(i!=c)
|
||||
{
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
SetBlock(r, i, GetBlock(r, c));
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/* DO NOTHING IF ALL COLUMNS ARE NON EMPTY
|
||||
*/
|
||||
|
||||
if(i==BOARD_COLS)
|
||||
return;
|
||||
|
||||
/* CALCULATE WHERE TO PUT THE COLUMNS
|
||||
*/
|
||||
|
||||
pos=(BOARD_COLS-i)/2;
|
||||
|
||||
/* COPY COLUMNS WITHOUT OVERLAP
|
||||
*/
|
||||
|
||||
cols=i;
|
||||
|
||||
for(c=pos+i-1; i!=-1; --c)
|
||||
{
|
||||
--i;
|
||||
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
SetBlock(r, c, GetBlock(r, i));
|
||||
}
|
||||
|
||||
/* EMPTY COLUMNS TO THE LEFT
|
||||
*/
|
||||
|
||||
for(c=0; c!=pos; ++c)
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
SetBlock(r, c, BLOCK_EMPTY);
|
||||
|
||||
/* EMPTY COLUMNS TO THE RIGHT
|
||||
*/
|
||||
|
||||
for(c=pos+cols; c!=BOARD_COLS; ++c)
|
||||
for(r=0; r!=BOARD_ROWS; ++r)
|
||||
SetBlock(r, c, BLOCK_EMPTY);
|
||||
}
|
||||
|
||||
/* PRINT HOW MANY BLOCKS ARE REMAINING
|
||||
*/
|
||||
|
||||
PrintBlocks()
|
||||
{
|
||||
char str[6];
|
||||
|
||||
sprintf(str, "%d ", blocks);
|
||||
|
||||
ScrOutStrRC(LEVEL_ROW+1, LEVEL_COL, str);
|
||||
}
|
||||
|
||||
/* PRINT SCORE
|
||||
*/
|
||||
|
||||
PrintScore()
|
||||
{
|
||||
char str[6];
|
||||
|
||||
sprintf(str, "%5d", score);
|
||||
|
||||
ScrOutStrRC(SCORE_ROW+1, SCORE_COL, str);
|
||||
}
|
||||
|
||||
/* PRINT SELECTION INFO.
|
||||
*/
|
||||
|
||||
PrintSelec()
|
||||
{
|
||||
char str[7];
|
||||
|
||||
sprintf(str, "x%d ", selected);
|
||||
|
||||
ScrOutStrRC(LEVEL_ROW+3, LEVEL_COL, str);
|
||||
|
||||
sprintf(str, "%5d+", add_to_score);
|
||||
|
||||
ScrOutStrRC(SCORE_ROW+3, SCORE_COL-1, str);
|
||||
}
|
||||
|
||||
/* PRINT TEXT STRING (MESSAGE)
|
||||
*/
|
||||
|
||||
PrintMsg(str)
|
||||
char *str;
|
||||
{
|
||||
ScrSetRC(SCR_ROWS-4, 2);
|
||||
ScrOutRpt(' ', SCR_COLS-4);
|
||||
|
||||
ScrTitle(SCR_ROWS-4, str);
|
||||
}
|
203
Blocks/ctype.h
Normal file
203
Blocks/ctype.h
Normal file
@ -0,0 +1,203 @@
|
||||
/**
|
||||
* @file ctype.h
|
||||
* @brief Character tests and conversion functions.
|
||||
* @author Miguel I. Garcia Lopez / FloppySoftware
|
||||
*
|
||||
* Character tests and conversion functions, for MESCC (Mike's Enhanced
|
||||
* Small C Compiler for Z80 & CP/M).
|
||||
*
|
||||
* Revisions:
|
||||
* - 19 Dec 2000 : Last revision.
|
||||
* - 16 Apr 2007 : GPL'd.
|
||||
* - 15 Aug 2016 : Documented. GPL v3.
|
||||
*
|
||||
* Copyright (c) 1999-2016 Miguel I. Garcia Lopez / FloppySoftware.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.
|
||||
*
|
||||
* http://www.floppysoftware.es
|
||||
* floppysoftware@gmail.com
|
||||
*/
|
||||
#ifndef CTYPE_H
|
||||
|
||||
#define CTYPE_H
|
||||
|
||||
/**
|
||||
* @fn int isalpha(char ch)
|
||||
* @brief Test if ch is a letter.
|
||||
* @param ch - character to test
|
||||
* @return true or false
|
||||
*/
|
||||
#asm
|
||||
|
||||
isalpha
|
||||
ld a,l
|
||||
ld hl,0
|
||||
cp 'A'
|
||||
ret c
|
||||
cp 'Z'+1
|
||||
jr c,isalpha1
|
||||
cp 'a'
|
||||
ret c
|
||||
cp 'z'+1
|
||||
ret nc
|
||||
isalpha1
|
||||
inc l
|
||||
ret
|
||||
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn int isdigit(char ch)
|
||||
* @brief Test if ch is a decimal digit.
|
||||
* @param ch - character to test
|
||||
* @return true or false
|
||||
*/
|
||||
#asm
|
||||
|
||||
isdigit
|
||||
ld a,l
|
||||
ld hl,0
|
||||
cp '0'
|
||||
ret c
|
||||
cp '9'+1
|
||||
ret nc
|
||||
inc l
|
||||
ret
|
||||
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn int isxdigit(char ch)
|
||||
* @brief Test if ch is an hexadecimal digit.
|
||||
* @param ch - character to test
|
||||
* @return true or false
|
||||
*/
|
||||
#asm
|
||||
|
||||
isxdigit
|
||||
LD C,L
|
||||
CALL isdigit
|
||||
RET C
|
||||
LD HL,0
|
||||
LD A,C
|
||||
CP 'A'
|
||||
RET C
|
||||
CP 'G'
|
||||
JR C,isxdigit1
|
||||
CP 'a'
|
||||
RET C
|
||||
CP 'g'
|
||||
RET NC
|
||||
isxdigit1
|
||||
INC L
|
||||
RET
|
||||
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn int isalnum(char ch)
|
||||
* @brief Test if ch is a letter or a decimal digit.
|
||||
* @param ch - character to test
|
||||
* @return true or false
|
||||
*/
|
||||
#asm
|
||||
|
||||
isalnum
|
||||
LD C,L
|
||||
CALL isdigit
|
||||
RET C
|
||||
LD L,C
|
||||
JP isalpha
|
||||
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn int isupper(char ch)
|
||||
* @brief Test if ch is a letter in uppercase.
|
||||
* @param ch - character to test
|
||||
* @return true or false
|
||||
*/
|
||||
#asm
|
||||
|
||||
isupper
|
||||
ld a,l
|
||||
ld hl,0
|
||||
cp 'A'
|
||||
ret c
|
||||
cp 'Z'+1
|
||||
ret nc
|
||||
inc l
|
||||
ret
|
||||
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn int islower(char ch)
|
||||
* @brief Test if ch is a letter in lowercase.
|
||||
* @param ch - character to test
|
||||
* @return true or false
|
||||
*/
|
||||
#asm
|
||||
|
||||
islower
|
||||
ld a,l
|
||||
ld hl,0
|
||||
cp 'a'
|
||||
ret c
|
||||
cp 'z'+1
|
||||
ret nc
|
||||
inc l
|
||||
ret
|
||||
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn int toupper(char ch)
|
||||
* @brief Convert letter to uppercase.
|
||||
*
|
||||
* If ch is not a letter in lowercase, returns ch unchanged.
|
||||
*
|
||||
* @param ch - character to convert
|
||||
* @return ch in uppercase
|
||||
*/
|
||||
#asm
|
||||
|
||||
toupper
|
||||
ld a,l
|
||||
cp 'a'
|
||||
ret c
|
||||
cp 'z'+1
|
||||
ret nc
|
||||
sub 20h
|
||||
ld l,a
|
||||
ret
|
||||
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn int tolower(char ch)
|
||||
* @brief Convert letter to lowercase.
|
||||
*
|
||||
* If ch is not a letter in uppercase, returns ch unchanged.
|
||||
*
|
||||
* @param ch - character to convert
|
||||
* @return ch in lowercase
|
||||
*/
|
||||
#asm
|
||||
|
||||
tolower
|
||||
ld a,l
|
||||
cp 'A'
|
||||
ret c
|
||||
cp 'Z'+1
|
||||
ret nc
|
||||
add 20h
|
||||
ld l,a
|
||||
ret
|
||||
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
|
158
Blocks/kslib.h
Normal file
158
Blocks/kslib.h
Normal file
@ -0,0 +1,158 @@
|
||||
/* kslib.h
|
||||
|
||||
Keyboard & screen functions library for CP/M & MESCC - Mike's Enhanced Small C Compiler.
|
||||
|
||||
Copyright (c) 2012 Miguel I. Garcia Lopez, Valencia, Spain.
|
||||
|
||||
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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Revisions:
|
||||
|
||||
02 Jul 2012 : Version 1.0 for 24x80 VT52 screen.
|
||||
10 Mar 2020 : Version 1.1 for 24x80 VT100 screen.
|
||||
|
||||
Functions:
|
||||
|
||||
int KbdScrStart(void)
|
||||
int KbdScrEnd(void)
|
||||
int KbdIn(void)
|
||||
int KbdChk(void)
|
||||
int KbdStat(void)
|
||||
void ScrOut(ch)
|
||||
void ScrOutStr(str)
|
||||
void ScrSetRC(row, col)
|
||||
void ScrCurOn(void)
|
||||
void ScrCurOff(void)
|
||||
void ScrClr(void)
|
||||
*/
|
||||
|
||||
#define SCR_ROWS 24
|
||||
#define SCR_COLS 80
|
||||
|
||||
#asm
|
||||
|
||||
xDirConInSt:
|
||||
jp 0
|
||||
xDirConIn:
|
||||
jp 0
|
||||
xDirConOut:
|
||||
jp 0
|
||||
|
||||
KbdScrStart:
|
||||
ld hl,(1)
|
||||
inc hl
|
||||
inc hl
|
||||
inc hl ;HL = JP CONST (BIOS VECTOR)
|
||||
ld de,xDirConInSt
|
||||
ld bc,9
|
||||
ldir
|
||||
ld hl,0 ;Success
|
||||
ret
|
||||
|
||||
KbdScrEnd:
|
||||
ld hl,0 ;Success
|
||||
ret
|
||||
|
||||
KbdIn:
|
||||
call xDirConIn
|
||||
KbdIn2:
|
||||
ld h,0
|
||||
ld l,a
|
||||
ret
|
||||
|
||||
KbdChk:
|
||||
call xDirConInSt
|
||||
ld h,0
|
||||
ld l,a
|
||||
ret
|
||||
|
||||
KbdStat:
|
||||
call xDirConInSt
|
||||
or a
|
||||
jr nz,KbdIn
|
||||
jr KbdIn2
|
||||
|
||||
ScrOut:
|
||||
ld c,l
|
||||
jp xDirConOut
|
||||
|
||||
ScrOutStr:
|
||||
ld a,(hl)
|
||||
or a
|
||||
ret z
|
||||
push hl
|
||||
ld c,a
|
||||
call xDirConOut
|
||||
pop hl
|
||||
inc hl
|
||||
jr ScrOutStr
|
||||
|
||||
#endasm
|
||||
|
||||
ScrSetRC(row, col)
|
||||
int row, col;
|
||||
{
|
||||
char str[9];
|
||||
sprintf(str, "%c[%d;%dH", 27, row+1, col+1);
|
||||
ScrOutStr(str);
|
||||
}
|
||||
|
||||
#asm
|
||||
|
||||
ScrCurOn:
|
||||
call xScrEsc
|
||||
ld c,'['
|
||||
call xDirConOut
|
||||
ld c,'?'
|
||||
call xDirConOut
|
||||
ld c,'2'
|
||||
call xDirConOut
|
||||
ld c,'5'
|
||||
call xDirConOut
|
||||
ld c,'h'
|
||||
jp xDirConOut
|
||||
|
||||
ScrCurOff:
|
||||
call xScrEsc
|
||||
ld c,'['
|
||||
call xDirConOut
|
||||
ld c,'?'
|
||||
call xDirConOut
|
||||
ld c,'2'
|
||||
call xDirConOut
|
||||
ld c,'5'
|
||||
call xDirConOut
|
||||
ld c,'l'
|
||||
jp xDirConOut
|
||||
|
||||
ScrClr:
|
||||
call xScrEsc
|
||||
ld c,'['
|
||||
call xDirConOut
|
||||
ld c,'2'
|
||||
call xDirConOut
|
||||
ld c,'J'
|
||||
call xDirConOut
|
||||
call xScrEsc
|
||||
ld c,'['
|
||||
call xDirConOut
|
||||
ld c,'H'
|
||||
jp xDirConOut
|
||||
|
||||
xScrEsc:
|
||||
ld c,27
|
||||
jp xDirConOut
|
||||
|
||||
#endasm
|
72
Blocks/kslibfun.h
Normal file
72
Blocks/kslibfun.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* kslibfun.h
|
||||
|
||||
More functions for kslib.h for CP/M and MESCC - Mike's Enhanced Small C Compiler.
|
||||
|
||||
Copyright (c) 2012 Miguel I. Garcia Lopez, Valencia, Spain.
|
||||
|
||||
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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Revisions:
|
||||
|
||||
02 Jul 2012 : Version 1.0.
|
||||
|
||||
Functions:
|
||||
|
||||
ScrOutRpt(ch, times)
|
||||
ScrOutStrRC(row, col, str)
|
||||
ScrBox(row, col, rows, cols, fill)
|
||||
ScrTitle(row, str)
|
||||
*/
|
||||
|
||||
ScrOutRpt(ch, times)
|
||||
int ch, times;
|
||||
{
|
||||
while(times--)
|
||||
ScrOut(ch);
|
||||
}
|
||||
|
||||
ScrOutStrRC(row, col, str)
|
||||
int row, col; char *str;
|
||||
{
|
||||
ScrSetRC(row, col); ScrOutStr(str);
|
||||
}
|
||||
|
||||
ScrBox(row, col, rows, cols, fill)
|
||||
int row, col, rows, cols, fill;
|
||||
{
|
||||
int i;
|
||||
|
||||
ScrSetRC(row++, col); ScrOut('+');
|
||||
ScrOutRpt('-', cols-2);
|
||||
ScrOut('+');
|
||||
|
||||
for(i=rows-2; i; --i)
|
||||
{
|
||||
ScrSetRC(row, col); ScrOut('|');
|
||||
if(fill!=NULL)
|
||||
ScrOutRpt(fill, cols-2);
|
||||
ScrSetRC(row++, col+cols-1); ScrOut('|');
|
||||
}
|
||||
|
||||
ScrSetRC(row, col); ScrOut('+');
|
||||
ScrOutRpt('-', cols-2);
|
||||
ScrOut('+');
|
||||
}
|
||||
|
||||
ScrTitle(row, str)
|
||||
int row; char *str;
|
||||
{
|
||||
ScrOutStrRC(row, (SCR_COLS-strlen(str))/2, str);
|
||||
}
|
945
Blocks/mescc.h
Normal file
945
Blocks/mescc.h
Normal file
@ -0,0 +1,945 @@
|
||||
/**
|
||||
* @file mescc.h
|
||||
* @brief Runtime library.
|
||||
* @author Miguel I. Garcia Lopez / FloppySoftware
|
||||
*
|
||||
* Runtime library for MESCC (Mike's Enhanced
|
||||
* Small C Compiler for Z80 & CP/M).
|
||||
*
|
||||
* This library file must be included first!
|
||||
*
|
||||
* Need following EQU's (generated by the compiler):
|
||||
* - ccSTACKSIZE : Stack size in bytes.
|
||||
*
|
||||
* Supports following #defs:
|
||||
* - #define CC_STDIO Support for stdin, stdout & stderr.
|
||||
* - #define CC_REDIR Support for stdin & stdout redirection
|
||||
* in command line (needs CC_STDIO).
|
||||
* - #define CC_NO_MUL To exclude MULTIPLICATION code.
|
||||
* - #define CC_NO_DIV To exclude DIVISION & MODULUS code.
|
||||
* - #define CC_NO_SWITCH To exclude SWITCH code.
|
||||
* - #define CC_NO_ARGS To exclude ARGC & ARGV code.
|
||||
* - #define CC_NO_ORG To exclude ORG 0100H code.
|
||||
*
|
||||
* Sets the following #defines:
|
||||
*
|
||||
* - BYTE
|
||||
* - WORD
|
||||
* - BOOL
|
||||
* - NULL
|
||||
* - TRUE
|
||||
* - FALSE
|
||||
* - SIZEOF_CHAR
|
||||
* - SIZEOF_INT
|
||||
* - SIZEOF_PTR
|
||||
*
|
||||
* Revisions:
|
||||
* - 16 Jan 2001 : Last revision.
|
||||
* - 23 Mar 2007 : Expand ccladr1 and ccladr2 for more speed.
|
||||
* - 16 Apr 2007 : GPL'd.
|
||||
* - 26 Aug 2012 : Added standard defs.
|
||||
* - 08 Dec 2014 : Minor changes.
|
||||
* - 09 Dec 2014 : Added support for stdin, stdout & stderr with CC_STDIO.
|
||||
* - 12 Dec 2014 : Added support for stdin & stdout redirection in command line with CC_REDIR.
|
||||
* - 16 Jan 2015 : Added SIZEOF_??? definitions.
|
||||
* - 16 Feb 2015 : Modified / added code in cctmpw, ccxpb2, ccxpb, ccxpb3, ccxpw2
|
||||
* ccxpw, ccxpw3, ccladr2sv, ccladr2, ccladr1sv, ccladr1,
|
||||
* to avoid use of IX register.
|
||||
* - 20 Mar 2015 : Added support for CC_NO_MUL, CC_NO_DIV, CC_NO_SWITCH, CC_NO_ARGS.
|
||||
* - 12 Apr 2015 : Removed ccDEFARGS code.
|
||||
* - 14 Jul 2015 : Modified code for << and >>, because a shift of 0 positions,
|
||||
* resulted in a wrong value (they assumed a shift > 0) - ie: 128 >> 0 resulted in 0.
|
||||
* - 19 Oct 2015 : Improved multiplication algorithm (ccmul & ccumul).
|
||||
* - 05 Nov 2015 : Modified ccsxt.
|
||||
* - 30 Nov 2015 : Added support for atexit().
|
||||
* - 24 Jan 2016 : Added support for CC_NO_ORG.
|
||||
* - 10 Dec 2016 : Documented. GPL v3.
|
||||
*
|
||||
* Copyright (c) 1999-2016 Miguel I. Garcia Lopez / FloppySoftware.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.
|
||||
*
|
||||
* http://www.floppysoftware.es
|
||||
* floppysoftware@gmail.com
|
||||
*/
|
||||
|
||||
/* STANDARD DEFs
|
||||
-------------
|
||||
*/
|
||||
|
||||
#define BYTE unsigned char
|
||||
#define WORD unsigned int
|
||||
#define BOOL char
|
||||
#define NULL 0
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define SIZEOF_CHAR 1 /* [unsigned] char */
|
||||
#define SIZEOF_INT 2 /* [unsigned] int */
|
||||
#define SIZEOF_PTR 2 /* pointer */
|
||||
|
||||
/* RUNTIME CODE
|
||||
------------
|
||||
*/
|
||||
|
||||
#ifndef CC_NO_ORG
|
||||
|
||||
#asm
|
||||
; Start at TPA
|
||||
|
||||
ORG 0100H
|
||||
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
#asm
|
||||
; Runtime address
|
||||
|
||||
ccrtadr:
|
||||
|
||||
; Set stack under BDOS (xx00h)
|
||||
|
||||
LD HL,(6)
|
||||
LD L,0
|
||||
LD SP,HL
|
||||
|
||||
; Leave space for stack and init. variables
|
||||
|
||||
LD DE,ccSTACKSIZE
|
||||
OR A
|
||||
SBC HL,DE
|
||||
DEC HL
|
||||
LD (ccfreelast),HL
|
||||
LD DE,ccfreemem
|
||||
LD (ccfreefirst),DE
|
||||
OR A
|
||||
SBC HL,DE
|
||||
INC HL
|
||||
LD (ccfreebytes),HL
|
||||
JR NC,ccargs
|
||||
|
||||
; Error, no memory for stack
|
||||
|
||||
LD C,9
|
||||
LD DE,ccerrstack
|
||||
CALL 5
|
||||
JP 0
|
||||
|
||||
ccerrstack
|
||||
DEFB 'Runtime Error - No stack$'
|
||||
|
||||
; Setup command line arguments
|
||||
|
||||
ccargs
|
||||
|
||||
#endasm
|
||||
|
||||
#ifndef CC_NO_ARGS
|
||||
|
||||
#asm
|
||||
; Copy command line
|
||||
|
||||
LD HL,81H
|
||||
LD DE,ccmdbuf
|
||||
LD BC,127
|
||||
LDIR
|
||||
|
||||
LD A,(80H)
|
||||
LD B,0
|
||||
LD C,A
|
||||
LD HL,ccmdbuf
|
||||
ADD HL,BC
|
||||
LD (HL),0
|
||||
|
||||
; Init. argc & argv
|
||||
|
||||
LD DE,cchptr
|
||||
LD HL,ccmdbuf - 1
|
||||
LD BC,1
|
||||
ccspc
|
||||
INC HL
|
||||
LD A,(HL)
|
||||
OR A
|
||||
JR Z,ccarg
|
||||
CP ' '
|
||||
JR Z,ccspc
|
||||
LD A,L
|
||||
LD (DE),A
|
||||
LD A,H
|
||||
INC DE
|
||||
LD (DE),A
|
||||
INC DE
|
||||
INC C
|
||||
ccpar
|
||||
INC HL
|
||||
LD A,(HL)
|
||||
OR A
|
||||
JR Z,ccarg
|
||||
CP ' '
|
||||
JR NZ,ccpar
|
||||
LD (HL),0
|
||||
JR ccspc
|
||||
|
||||
ccarg
|
||||
LD HL,cchptr - 2
|
||||
PUSH BC ;argc
|
||||
PUSH HL ;argv
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CC_REDIR
|
||||
|
||||
#asm
|
||||
CALL redir ;FIXME - Check errors
|
||||
POP DE
|
||||
POP BC
|
||||
PUSH HL ;argc
|
||||
PUSH DE ;argv
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
#asm
|
||||
|
||||
; Execute program
|
||||
|
||||
CALL main
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn void exit(int code)
|
||||
* @brief Exit to CP/M.
|
||||
*
|
||||
* FixMe: Return code is lost!
|
||||
*/
|
||||
#asm
|
||||
|
||||
; Exit to CP/M
|
||||
|
||||
exit
|
||||
NOP ; Patch for atexit() -- 3 bytes.
|
||||
NOP
|
||||
NOP
|
||||
#endasm
|
||||
|
||||
#ifdef CC_STDIO
|
||||
|
||||
BYTE *stdin, *stdout, *stderr; /* Sorry, no available FILE here */
|
||||
|
||||
#asm
|
||||
LD HL,(stdin)
|
||||
CALL ccflush
|
||||
LD HL,(stdout)
|
||||
CALL ccflush
|
||||
|
||||
JP 0
|
||||
|
||||
ccflush
|
||||
LD A,H
|
||||
OR L
|
||||
RET Z
|
||||
PUSH HL
|
||||
CALL fclose
|
||||
POP BC
|
||||
RET
|
||||
#endasm
|
||||
|
||||
#else
|
||||
|
||||
#asm
|
||||
JP 0
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
#asm
|
||||
|
||||
; Variables for memory functions
|
||||
|
||||
ccfreefirst
|
||||
DEFW 0 ;Adr. first free byte
|
||||
ccfreelast
|
||||
DEFW 0 ;Adr. last free byte
|
||||
ccfreebytes
|
||||
DEFW 0 ;Number of free bytes
|
||||
|
||||
#endasm
|
||||
|
||||
#ifndef CC_NO_ARGS
|
||||
|
||||
#asm
|
||||
; Variables for command line arguments
|
||||
|
||||
ccmdbuf
|
||||
DEFS 128 ;Command line buffer
|
||||
|
||||
DEFW ccNULL ;Pointers table for argv
|
||||
cchptr
|
||||
DEFW ccNULL,ccNULL,ccNULL,ccNULL,ccNULL
|
||||
DEFW ccNULL,ccNULL,ccNULL,ccNULL,ccNULL
|
||||
DEFW ccNULL,ccNULL,ccNULL,ccNULL,ccNULL
|
||||
DEFW ccNULL,ccNULL,ccNULL,ccNULL,ccNULL
|
||||
DEFW ccNULL,ccNULL,ccNULL,ccNULL,ccNULL
|
||||
|
||||
ccNULL
|
||||
DEFB 0 ;Null pointer
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
#asm
|
||||
|
||||
; Basic routines
|
||||
|
||||
; Call formats to access locals:
|
||||
;
|
||||
; Format 1: CALL routine
|
||||
; DEFB SpOffset
|
||||
;
|
||||
; Format 2: CALL routine
|
||||
; DEFW SpOffset
|
||||
|
||||
; HL = unsigned char from local (format 2)
|
||||
|
||||
ccxgb2
|
||||
CALL ccladr2
|
||||
JR ccxgb3
|
||||
|
||||
; HL = unsigned char from local (format 1)
|
||||
|
||||
ccxgb
|
||||
CALL ccladr1
|
||||
ccxgb3
|
||||
LD L,(HL)
|
||||
LD H,0
|
||||
RET
|
||||
|
||||
; HL = signed char from local (format 2)
|
||||
|
||||
ccxgc2
|
||||
CALL ccladr2
|
||||
JR ccgc
|
||||
|
||||
; HL = signed char from local (format 1)
|
||||
|
||||
ccxgc
|
||||
CALL ccladr1
|
||||
|
||||
; HL = signed char from (HL)
|
||||
|
||||
ccgc
|
||||
LD A,(HL)
|
||||
|
||||
; HL = signed char from A
|
||||
|
||||
ccsxt
|
||||
LD L,A
|
||||
RLCA
|
||||
SBC A
|
||||
LD H,A
|
||||
RET
|
||||
|
||||
; LD H,0
|
||||
; LD L,A
|
||||
; AND 128
|
||||
; RET Z
|
||||
; DEC H
|
||||
; RET
|
||||
|
||||
; HL = word from local (format 2)
|
||||
|
||||
ccxgw2
|
||||
CALL ccladr2
|
||||
JR ccgw
|
||||
|
||||
; HL = word from local (format 1)
|
||||
|
||||
ccxgw
|
||||
CALL ccladr1
|
||||
|
||||
; HL = word from (HL)
|
||||
|
||||
ccgw
|
||||
LD A,(HL)
|
||||
INC HL
|
||||
LD H,(HL)
|
||||
LD L,A
|
||||
RET
|
||||
|
||||
; char local = HL (format 2)
|
||||
|
||||
ccxpb2
|
||||
CALL ccladr2sv
|
||||
JR ccxpb3
|
||||
|
||||
; char local = HL (format 1)
|
||||
|
||||
ccxpb
|
||||
CALL ccladr1sv
|
||||
ccxpb3
|
||||
LD DE,(cctmpw)
|
||||
LD (HL),E
|
||||
EX DE,HL
|
||||
RET
|
||||
|
||||
; int/ptr local = HL (format 2)
|
||||
|
||||
ccxpw2
|
||||
CALL ccladr2sv
|
||||
JR ccxpw3
|
||||
|
||||
; int/ptr local = HL (format 1)
|
||||
|
||||
ccxpw
|
||||
CALL ccladr1sv
|
||||
ccxpw3
|
||||
LD DE,(cctmpw)
|
||||
LD (HL),E
|
||||
INC HL
|
||||
LD (HL),D
|
||||
EX DE,HL
|
||||
RET
|
||||
|
||||
; Copy 1 word from HL to (DE)
|
||||
|
||||
ccpw
|
||||
LD A,L
|
||||
LD (DE),A
|
||||
INC DE
|
||||
LD A,H
|
||||
LD (DE),A
|
||||
RET
|
||||
|
||||
; Calc. local adress
|
||||
|
||||
cctmpw DEFW 0
|
||||
|
||||
ccladr2sv
|
||||
LD (cctmpw),HL
|
||||
|
||||
ccladr2
|
||||
POP DE
|
||||
POP HL
|
||||
LD C,(HL)
|
||||
INC HL
|
||||
LD B,(HL)
|
||||
INC HL
|
||||
PUSH HL
|
||||
PUSH DE
|
||||
LD HL,4
|
||||
ADD HL,BC
|
||||
ADD HL,SP
|
||||
RET
|
||||
|
||||
ccladr1sv
|
||||
LD (cctmpw),HL
|
||||
|
||||
ccladr1
|
||||
POP DE
|
||||
POP HL
|
||||
LD B,0
|
||||
LD C,(HL)
|
||||
INC HL
|
||||
PUSH HL
|
||||
PUSH DE
|
||||
LD HL,4
|
||||
ADD HL,BC
|
||||
ADD HL,SP
|
||||
RET
|
||||
|
||||
; OR HL = HL | DE
|
||||
|
||||
ccor
|
||||
LD A,L
|
||||
OR E
|
||||
LD L,A
|
||||
LD A,H
|
||||
OR D
|
||||
LD H,A
|
||||
RET
|
||||
|
||||
; XOR HL = HL ^ DE
|
||||
|
||||
ccxor
|
||||
LD A,L
|
||||
XOR E
|
||||
LD L,A
|
||||
LD A,H
|
||||
XOR D
|
||||
LD H,A
|
||||
RET
|
||||
|
||||
; AND HL = HL & DE
|
||||
|
||||
ccand
|
||||
LD A,L
|
||||
AND E
|
||||
LD L,A
|
||||
LD A,H
|
||||
AND D
|
||||
LD H,A
|
||||
RET
|
||||
|
||||
; LOGIC OR HL = DE || HL
|
||||
|
||||
cclgor
|
||||
LD A,H
|
||||
OR L
|
||||
OR D
|
||||
OR E
|
||||
LD L,A
|
||||
RET
|
||||
|
||||
;LD A,H
|
||||
;OR L
|
||||
;RET NZ
|
||||
;LD A,D
|
||||
;OR E
|
||||
;RET Z
|
||||
;INC L
|
||||
;RET
|
||||
|
||||
; LOGIC AND HL = DE && HL
|
||||
|
||||
cclgand
|
||||
LD A,H
|
||||
OR L
|
||||
RET Z
|
||||
LD A,D
|
||||
OR E
|
||||
RET NZ
|
||||
JP ccfalse
|
||||
|
||||
; HL = HL == DE
|
||||
|
||||
cceq
|
||||
OR A
|
||||
SBC HL,DE
|
||||
|
||||
; LOGIC NOT HL = !HL
|
||||
|
||||
cclgnot
|
||||
LD A,H
|
||||
OR L
|
||||
JP NZ,ccfalse
|
||||
INC L
|
||||
RET
|
||||
|
||||
; HL = HL != DE
|
||||
|
||||
ccne
|
||||
OR A
|
||||
SBC HL,DE
|
||||
RET
|
||||
|
||||
; HL = DE > HL (SIGNED)
|
||||
|
||||
ccgt
|
||||
EX DE,HL
|
||||
|
||||
; HL = DE < HL (SIGNED)
|
||||
|
||||
cclt
|
||||
CALL cccmp
|
||||
RET C
|
||||
DEC L
|
||||
RET
|
||||
|
||||
; HL = DE <= HL (SIGNED)
|
||||
|
||||
ccle
|
||||
CALL cccmp
|
||||
RET Z
|
||||
RET C
|
||||
DEC L
|
||||
RET
|
||||
|
||||
; HL = DE >= HL (SIGNED)
|
||||
|
||||
ccge
|
||||
CALL cccmp
|
||||
RET NC
|
||||
DEC L
|
||||
RET
|
||||
|
||||
; Compare DE with HL, and return: (SIGNED)
|
||||
;
|
||||
; CARRY if DE < HL
|
||||
; ZERO if DE == HL
|
||||
; HL = 1
|
||||
|
||||
cccmp
|
||||
LD A,E
|
||||
SUB L
|
||||
LD E,A
|
||||
LD A,D
|
||||
SBC H
|
||||
LD HL,1
|
||||
JP M,cccmp1
|
||||
OR E
|
||||
RET
|
||||
|
||||
cccmp1
|
||||
OR E
|
||||
SCF
|
||||
RET
|
||||
|
||||
; HL = DE <= HL (UNSIGNED)
|
||||
|
||||
ccule
|
||||
CALL ccucmp
|
||||
RET Z
|
||||
RET C
|
||||
DEC L
|
||||
RET
|
||||
|
||||
; HL = DE >= HL (UNSIGNED)
|
||||
|
||||
ccuge
|
||||
CALL ccucmp
|
||||
RET NC
|
||||
DEC L
|
||||
RET
|
||||
|
||||
; HL = DE > HL (UNSIGNED)
|
||||
|
||||
ccugt
|
||||
EX DE,HL
|
||||
|
||||
; HL = DE < HL (UNSIGNED)
|
||||
|
||||
ccult
|
||||
CALL ccucmp
|
||||
RET C
|
||||
DEC L
|
||||
RET
|
||||
|
||||
; Compare DE with HL, and return: (UNSIGNED)
|
||||
;
|
||||
; CARRY if DE < HL
|
||||
; ZERO if DE == HL
|
||||
; HL = 1
|
||||
|
||||
ccucmp
|
||||
LD A,D
|
||||
CP H
|
||||
JR NZ,ccucmp1
|
||||
LD A,E
|
||||
CP L
|
||||
|
||||
ccucmp1
|
||||
LD HL,1
|
||||
RET
|
||||
|
||||
; HL = DE >> HL (UNSIGNED)
|
||||
|
||||
ccuasr
|
||||
EX DE,HL
|
||||
LD A,E
|
||||
ccuasr1
|
||||
OR A
|
||||
RET Z
|
||||
DEC A
|
||||
SRL H
|
||||
RR L
|
||||
JR ccuasr1
|
||||
|
||||
; HL = DE >> HL (ARITMETIC)
|
||||
|
||||
ccasr
|
||||
EX DE,HL
|
||||
LD A,E
|
||||
ccasr1
|
||||
OR A
|
||||
RET Z
|
||||
DEC A
|
||||
SRA H
|
||||
RR L
|
||||
JR ccasr1
|
||||
|
||||
; HL = DE << HL (UNSIGNED)
|
||||
|
||||
ccuasl
|
||||
|
||||
; HL = DE << HL (ARITMETIC)
|
||||
|
||||
ccasl
|
||||
EX DE,HL
|
||||
LD A,E
|
||||
ccasl1
|
||||
OR A
|
||||
RET Z
|
||||
DEC A
|
||||
ADD HL,HL
|
||||
JR ccasl1
|
||||
|
||||
; HL = DE - HL
|
||||
|
||||
ccsub
|
||||
EX DE,HL
|
||||
OR A
|
||||
SBC HL,DE
|
||||
RET
|
||||
|
||||
; HL = ~HL (1 COMPLEMENT)
|
||||
|
||||
cccom
|
||||
LD A,H
|
||||
CPL
|
||||
LD H,A
|
||||
LD A,L
|
||||
CPL
|
||||
LD L,A
|
||||
RET
|
||||
|
||||
; HL = -HL (2 COMPLEMENT)
|
||||
|
||||
ccneg
|
||||
LD A,H
|
||||
CPL
|
||||
LD H,A
|
||||
LD A,L
|
||||
CPL
|
||||
LD L,A
|
||||
INC HL
|
||||
RET
|
||||
|
||||
#endasm
|
||||
|
||||
#ifndef CC_NO_MUL
|
||||
|
||||
#asm
|
||||
|
||||
; HL = DE * HL (UNSIGNED)
|
||||
|
||||
ccumul
|
||||
|
||||
; HL = DE * HL (SIGNED)
|
||||
|
||||
ccmul
|
||||
LD A,H
|
||||
LD C,L
|
||||
LD HL,0
|
||||
LD B,16
|
||||
ccmul0
|
||||
ADD HL,HL
|
||||
SLA C
|
||||
RL A
|
||||
JR NC,ccmul1
|
||||
ADD HL,DE
|
||||
ccmul1
|
||||
DJNZ ccmul0
|
||||
RET
|
||||
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef CC_NO_DIV
|
||||
|
||||
#asm
|
||||
|
||||
; HL = DE % HL (SIGNED)
|
||||
|
||||
ccmod
|
||||
CALL ccdiv
|
||||
EX DE,HL
|
||||
RET
|
||||
|
||||
; HL = DE / HL (SIGNED)
|
||||
; DE = DE % HL (SIGNED)
|
||||
|
||||
ccdiv
|
||||
LD B,H
|
||||
LD C,L
|
||||
LD A,D
|
||||
XOR B
|
||||
PUSH AF
|
||||
LD A,D
|
||||
OR A
|
||||
CALL M,ccdivdeneg
|
||||
LD A,B
|
||||
OR A
|
||||
|
||||
JP P,ccdiv0
|
||||
|
||||
LD A,B
|
||||
CPL
|
||||
LD B,A
|
||||
LD A,C
|
||||
CPL
|
||||
LD C,A
|
||||
INC BC
|
||||
|
||||
ccdiv0
|
||||
EX DE,HL
|
||||
LD DE,0
|
||||
LD A,16
|
||||
|
||||
ccdiv1
|
||||
PUSH AF
|
||||
|
||||
ADD HL,HL
|
||||
|
||||
RL E
|
||||
RL D
|
||||
LD A,D
|
||||
OR E
|
||||
|
||||
JR Z,ccdiv2
|
||||
|
||||
LD A,E
|
||||
SUB C
|
||||
LD A,D
|
||||
SBC B
|
||||
|
||||
JP M,ccdiv2
|
||||
LD A,L
|
||||
OR 1
|
||||
LD L,A
|
||||
LD A,E
|
||||
SUB C
|
||||
LD E,A
|
||||
LD A,D
|
||||
SBC B
|
||||
LD D,A
|
||||
|
||||
ccdiv2
|
||||
POP AF
|
||||
DEC A
|
||||
JR NZ,ccdiv1
|
||||
POP AF
|
||||
RET P
|
||||
|
||||
CALL ccneg
|
||||
|
||||
ccdivdeneg
|
||||
LD A,D
|
||||
CPL
|
||||
LD D,A
|
||||
LD A,E
|
||||
CPL
|
||||
LD E,A
|
||||
INC DE
|
||||
RET
|
||||
|
||||
; HL = DE % HL (UNSIGNED)
|
||||
|
||||
ccumod
|
||||
CALL ccudiv
|
||||
EX DE,HL
|
||||
RET
|
||||
|
||||
; HL = DE / HL (UNSIGNED)
|
||||
; DE = DE % HL (UNSIGNED)
|
||||
|
||||
ccudiv
|
||||
LD (ccudiv_tmp),HL
|
||||
LD HL,ccudiv_cnt
|
||||
LD (HL),17
|
||||
LD BC,0
|
||||
PUSH BC
|
||||
XOR A
|
||||
|
||||
ccudiv0
|
||||
RL E
|
||||
RL D
|
||||
DEC (HL)
|
||||
POP HL
|
||||
JR Z,ccudiv2
|
||||
LD A,0
|
||||
ADC 0
|
||||
ADD HL,HL
|
||||
LD B,H
|
||||
ADD L
|
||||
LD HL,(ccudiv_tmp)
|
||||
SUB L
|
||||
LD C,A
|
||||
LD A,B
|
||||
SBC H
|
||||
LD B,A
|
||||
PUSH BC
|
||||
JR NC,ccudiv1
|
||||
ADD HL,BC
|
||||
EX (SP),HL
|
||||
|
||||
ccudiv1
|
||||
LD HL,ccudiv_cnt
|
||||
CCF
|
||||
JR ccudiv0
|
||||
|
||||
ccudiv2
|
||||
EX DE,HL
|
||||
RET
|
||||
|
||||
ccudiv_tmp
|
||||
DEFW 0
|
||||
ccudiv_cnt
|
||||
DEFB 0
|
||||
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef CC_NO_SWITCH
|
||||
|
||||
#asm
|
||||
|
||||
; Switch, on entry:
|
||||
;
|
||||
; DE = Table address
|
||||
; HL = Where to go if value was not found in table
|
||||
; B = Number of entries in table
|
||||
|
||||
ccswtch
|
||||
EX (SP),HL
|
||||
EX DE,HL
|
||||
|
||||
ccswch1
|
||||
LD A,E
|
||||
CP (HL)
|
||||
INC HL
|
||||
JR NZ,ccswch2
|
||||
LD A,D
|
||||
CP (HL)
|
||||
JR NZ,ccswch2
|
||||
INC HL
|
||||
LD E,(HL)
|
||||
INC HL
|
||||
LD D,(HL)
|
||||
EX DE,HL
|
||||
POP BC
|
||||
JP (HL)
|
||||
|
||||
ccswch2
|
||||
INC HL
|
||||
INC HL
|
||||
INC HL
|
||||
DJNZ ccswch1
|
||||
EX (SP),HL
|
||||
POP BC
|
||||
JP (HL)
|
||||
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
#asm
|
||||
|
||||
; HL = TRUE
|
||||
|
||||
cctrue
|
||||
LD L,1
|
||||
RET
|
||||
|
||||
; HL = FALSE
|
||||
|
||||
ccfalse
|
||||
LD HL,0
|
||||
RET
|
||||
|
||||
#endasm
|
||||
|
||||
|
104
Blocks/sprintf.h
Normal file
104
Blocks/sprintf.h
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @file sprintf.h
|
||||
* @brief Library for sprintf() function.
|
||||
* @author Miguel I. Garcia Lopez / FloppySoftware
|
||||
*
|
||||
* Implementation of sprintf() function, for MESCC (Mike's Enhanced
|
||||
* Small C Compiler for Z80 & CP/M).
|
||||
*
|
||||
* Revisions:
|
||||
* - 20 Oct 2000 : Last revision.
|
||||
* - 16 Apr 2007 : GPL'd.
|
||||
* - 14 Apr 2015 : Ammended a bad closed comment.
|
||||
* - 25 Aug 2016 : Documented. GPL v3.
|
||||
*
|
||||
* Copyright (c) 1999-2016 Miguel I. Garcia Lopez / FloppySoftware.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.
|
||||
*
|
||||
* http://www.floppysoftware.es
|
||||
* floppysoftware@gmail.com
|
||||
*/
|
||||
#ifndef SPRINTF_H
|
||||
|
||||
#define SPRINTF_H
|
||||
|
||||
// Dependencies
|
||||
// ------------
|
||||
|
||||
#ifndef XPRINTF_H
|
||||
#include <xprintf.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @fn int sprintf(char *dst, char *fmt, arg1, arg2, ...)
|
||||
* @brief Formatted output to memory.
|
||||
*
|
||||
* See the documentation for xprintf.h to learn about the string format.
|
||||
*
|
||||
* @param dst - destination
|
||||
* @param fmt - string format
|
||||
* @param arg1 - argument #1
|
||||
* @param arg? - argument #?
|
||||
* @return number or characters written, or -1 on failure (currently always #).
|
||||
*/
|
||||
#asm
|
||||
|
||||
sprintf:
|
||||
ADD HL,HL
|
||||
ADD HL,SP ;HL=Adr. fmt
|
||||
|
||||
LD DE,xspfout
|
||||
PUSH DE
|
||||
LD DE,xspfend
|
||||
PUSH DE
|
||||
PUSH HL
|
||||
|
||||
INC HL
|
||||
INC HL ;HL=Adr. dst
|
||||
LD A,(HL)
|
||||
INC HL
|
||||
LD H,(HL)
|
||||
LD L,A
|
||||
LD (xspfout+2),HL
|
||||
|
||||
CALL xprintf
|
||||
|
||||
POP BC
|
||||
POP BC
|
||||
POP BC
|
||||
|
||||
RET
|
||||
#endasm
|
||||
|
||||
// int xspfout(char ch) : output ch to memory; return 0 on success, !=0 on failure (currently always returns 0).
|
||||
|
||||
#asm
|
||||
|
||||
xspfout:
|
||||
LD A,L
|
||||
LD HL,0 ;Adr.
|
||||
LD (HL),A
|
||||
|
||||
INC HL
|
||||
LD (xspfout+2),HL
|
||||
|
||||
LD HL,0
|
||||
|
||||
RET
|
||||
#endasm
|
||||
|
||||
// void xspfend(void) : end formatted output; writes a trailing zero byte.
|
||||
|
||||
#asm
|
||||
|
||||
xspfend:
|
||||
LD HL,(xspfout+2)
|
||||
LD (HL),0
|
||||
RET
|
||||
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
|
249
Blocks/string.h
Normal file
249
Blocks/string.h
Normal file
@ -0,0 +1,249 @@
|
||||
/**
|
||||
* @file string.h
|
||||
* @brief String functions.
|
||||
* @author Miguel I. Garcia Lopez / FloppySoftware
|
||||
*
|
||||
* String functions, for MESCC (Mike's Enhanced
|
||||
* Small C Compiler for Z80 & CP/M).
|
||||
*
|
||||
* Revisions:
|
||||
* - 19 Mar 2001 : Last revision.
|
||||
* - 16 Apr 2007 : GPL'd.
|
||||
* - 15 Aug 2016 : Documented. GPL v3.
|
||||
*
|
||||
* Copyright (c) 1999-2016 Miguel I. Garcia Lopez / FloppySoftware.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.
|
||||
*
|
||||
* http://www.floppysoftware.es
|
||||
* floppysoftware@gmail.com
|
||||
*/
|
||||
#ifndef STRING_H
|
||||
|
||||
#define STRING_H
|
||||
|
||||
/**
|
||||
* @fn int strlen(char *str)
|
||||
* @brief Return string length.
|
||||
* @param str - string
|
||||
* @return length in characters
|
||||
*/
|
||||
#asm
|
||||
strlen:
|
||||
LD D,H
|
||||
LD E,L
|
||||
LD BC,0FFFFH
|
||||
XOR A
|
||||
CPIR
|
||||
OR A
|
||||
SBC HL,DE
|
||||
DEC HL
|
||||
RET
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn char *strcpy(char *dst, char *src)
|
||||
* @brief Copy string.
|
||||
* @param dst - destination string
|
||||
* @param src - source string
|
||||
* @return pointer to dst
|
||||
*/
|
||||
#asm
|
||||
strcpy:
|
||||
POP BC
|
||||
POP HL
|
||||
POP DE
|
||||
PUSH DE
|
||||
PUSH HL
|
||||
PUSH BC
|
||||
|
||||
PUSH DE
|
||||
|
||||
strcpy2:
|
||||
LD A,(HL)
|
||||
LD (DE),A
|
||||
INC HL
|
||||
INC DE
|
||||
OR A
|
||||
JR NZ,strcpy2
|
||||
POP HL
|
||||
RET
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn char *strcat(char *dst, char *src)
|
||||
* @brief Copy string at the end of another string.
|
||||
* @param dst - destination string
|
||||
* @param src - source string
|
||||
* @return pointer to dst
|
||||
*/
|
||||
#asm
|
||||
strcat:
|
||||
POP BC
|
||||
POP HL
|
||||
POP DE
|
||||
PUSH DE
|
||||
PUSH HL
|
||||
PUSH BC
|
||||
|
||||
PUSH DE
|
||||
|
||||
strcat2
|
||||
LD A,(DE)
|
||||
OR A
|
||||
JR Z,strcpy2
|
||||
INC DE
|
||||
JR strcat2
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn int strcmp(char *str1, char *str2)
|
||||
* @brief Compare two strings.
|
||||
* @param str1 - a string
|
||||
* @param str2 - a string
|
||||
* @return <0 on str1 < str2; =0 on str1 == str2; >0 on str1 > str2
|
||||
*/
|
||||
#asm
|
||||
strcmp
|
||||
POP BC
|
||||
POP HL
|
||||
POP DE
|
||||
PUSH DE
|
||||
PUSH HL
|
||||
PUSH BC
|
||||
strcmp1
|
||||
LD A,(DE)
|
||||
CP (HL)
|
||||
JR NZ,strcmp2
|
||||
|
||||
OR A
|
||||
JR Z,strcmp2
|
||||
|
||||
INC DE
|
||||
INC HL
|
||||
JR strcmp1
|
||||
|
||||
strcmp2
|
||||
LD HL,0
|
||||
RET Z
|
||||
JR NC,strcmp3
|
||||
DEC HL
|
||||
RET
|
||||
strcmp3
|
||||
INC L
|
||||
RET
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn char *strchr(char *str, char ch)
|
||||
* @brief Search a character in a string.
|
||||
* @param str - the string where to search
|
||||
* @param ch - the character to find
|
||||
* @return pointer to ch in the string, or NULL on failure
|
||||
*/
|
||||
#asm
|
||||
strchr
|
||||
POP BC
|
||||
POP DE
|
||||
POP HL
|
||||
PUSH HL
|
||||
PUSH DE
|
||||
PUSH BC
|
||||
|
||||
|
||||
strchr2
|
||||
LD A,(HL)
|
||||
CP E
|
||||
RET Z
|
||||
|
||||
INC HL
|
||||
OR A
|
||||
JR NZ,strchr2
|
||||
|
||||
LD H,A
|
||||
LD L,A
|
||||
RET
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn char *strupr(char *str)
|
||||
* @brief Convert a string to upper case.
|
||||
* @param str - a string
|
||||
* @return pointer to str
|
||||
*/
|
||||
#asm
|
||||
strupr
|
||||
POP BC
|
||||
POP HL
|
||||
PUSH HL
|
||||
PUSH BC
|
||||
|
||||
PUSH HL
|
||||
|
||||
strupr1
|
||||
LD A,(HL)
|
||||
OR A
|
||||
JR Z,strupr3
|
||||
|
||||
CP 'a'
|
||||
JR C,strupr2
|
||||
CP 'z'+1
|
||||
JR NC,strupr2
|
||||
SUB 32
|
||||
LD (HL),A
|
||||
|
||||
strupr2
|
||||
INC HL
|
||||
JR strupr1
|
||||
|
||||
strupr3
|
||||
POP HL
|
||||
RET
|
||||
#endasm
|
||||
|
||||
/**
|
||||
* @fn int atoi(char *s)
|
||||
* @brief Convert string to a integer.
|
||||
*
|
||||
* This function parses a string, interpreting its content as
|
||||
* a decimal integer number, until the end of the string, or
|
||||
* a non decimal digit:
|
||||
*
|
||||
* [+|-][[0..9]...][ZERO|NON_DECIMAL_DIGIT]
|
||||
*
|
||||
* Examples:
|
||||
* - "-256" == -256
|
||||
* - "64" == 64
|
||||
* - "1024 bytes" == 1024
|
||||
* - "what?" == 0
|
||||
*
|
||||
* @param s - a string
|
||||
* @return integer value
|
||||
*/
|
||||
atoi(s)
|
||||
char *s;
|
||||
{
|
||||
int sign, val;
|
||||
|
||||
if(*s == '+')
|
||||
{
|
||||
++s; sign = 1;
|
||||
}
|
||||
else if(*s == '-')
|
||||
{
|
||||
++s; sign = -1;
|
||||
}
|
||||
else
|
||||
sign = 1;
|
||||
|
||||
val=0;
|
||||
|
||||
while(*s >= '0' && *s <= '9')
|
||||
val = val * 10 + (*s++ - '0');
|
||||
|
||||
return val * sign;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
365
Blocks/xprintf.h
Normal file
365
Blocks/xprintf.h
Normal file
@ -0,0 +1,365 @@
|
||||
/**
|
||||
* @file xprintf.h
|
||||
* @brief Support library for formatted output.
|
||||
* @author Miguel I. Garcia Lopez / FloppySoftware
|
||||
*
|
||||
* Support library for formatted output,
|
||||
* for MESCC (Mike's Enhanced Small C Compiler for Z80 & CP/M).
|
||||
*
|
||||
* All functions with formatted output like printf(), fprintf()
|
||||
* and sprintf() call some private functions in this order:
|
||||
* - pf_sf()
|
||||
* - pf_s()
|
||||
* - pf_out()
|
||||
*
|
||||
* Revisions:
|
||||
* - 19 Mar 2001 : Last revision.
|
||||
* - 16 Apr 2007 : GPL'd.
|
||||
* - 09 Dec 2016 : Documented. Optimized. GPL v3.
|
||||
* - 02 Aug 2017 : Output '%%' as '%'.
|
||||
*
|
||||
* Copyright (c) 1999-2016 Miguel I. Garcia Lopez / FloppySoftware.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3.
|
||||
*
|
||||
* http://www.floppysoftware.es
|
||||
* floppysoftware@gmail.com
|
||||
*/
|
||||
#ifndef XPRINTF_H
|
||||
|
||||
#define XPRINTF_H
|
||||
|
||||
// Dependencies
|
||||
// ------------
|
||||
|
||||
#ifndef STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
// Private globals
|
||||
// ---------------
|
||||
|
||||
BYTE xpf_err; // True on error
|
||||
|
||||
extern WORD xpf_out; // Output function
|
||||
extern WORD xpf_end; // End function
|
||||
|
||||
int xpf_fw; // Field width
|
||||
BYTE xpf_fa; // Field alignment: 0=left, 1=right
|
||||
BYTE xpf_fz; // True on zero filling
|
||||
|
||||
int xpf_cnt; // # of characters sent
|
||||
|
||||
/**
|
||||
* @fn int xprintf(WORD funout, WORD funend, WORD adrpars)
|
||||
* @brief Formatted output.
|
||||
*
|
||||
* This function performs formatted output. It is used
|
||||
* by printf(), fprintf() and sprintf() functions.
|
||||
*
|
||||
* The format is indicated in the string as follows:
|
||||
*
|
||||
* %[-][0][w]t
|
||||
*
|
||||
* | - : Left align (default: right align).
|
||||
* | 0 : Zero filling on right align.
|
||||
* | w : Width for alignment. If the specified width
|
||||
* | is lower than the argument length, output is
|
||||
* | done without aligment. Care with sprinf()!
|
||||
* | t : d = Signed decimal integer.
|
||||
* | u = Unsigned decimal integer.
|
||||
* | x = Hexadecimal integer.
|
||||
* | s = String.
|
||||
* | c = Character.
|
||||
*
|
||||
* The pair %% outputs a single %.
|
||||
*
|
||||
* @param funout - function to output a character
|
||||
* @param funend - function to end output
|
||||
* @param adrpars - arguments addresses
|
||||
* @return # of characters sent on sucess, -1 on failure
|
||||
*/
|
||||
xprintf(funout, funend, adrpars)
|
||||
WORD funout, funend;
|
||||
WORD *adrpars;
|
||||
{
|
||||
WORD *parg; // Pointer to arguments
|
||||
char *pfor; // Pointer to formatted string
|
||||
int ivalue;
|
||||
char ch;
|
||||
|
||||
// Setup
|
||||
xpf_out = funout;
|
||||
xpf_end = funend;
|
||||
|
||||
pfor = *adrpars;
|
||||
parg = --adrpars;
|
||||
|
||||
xpf_err = xpf_cnt = 0;
|
||||
|
||||
// Loop
|
||||
while((ch = *pfor++))
|
||||
{
|
||||
if(ch == '%')
|
||||
{
|
||||
// Character %
|
||||
if(*pfor == '%')
|
||||
{
|
||||
pf_out(ch);
|
||||
++pfor;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Align
|
||||
if(*pfor == '-')
|
||||
{
|
||||
xpf_fa = 0; // Left align
|
||||
++pfor;
|
||||
}
|
||||
else
|
||||
xpf_fa = 1; // Right align
|
||||
|
||||
// Zero filling
|
||||
if(*pfor == '0')
|
||||
{
|
||||
xpf_fz = 1; // Zero filling
|
||||
++pfor;
|
||||
}
|
||||
else
|
||||
xpf_fz = 0;
|
||||
|
||||
// Width
|
||||
xpf_fw = 0;
|
||||
|
||||
while(*pfor >= '0' && *pfor <= '9')
|
||||
xpf_fw = xpf_fw * 10 + (*pfor++) - '0';
|
||||
|
||||
// Type
|
||||
switch(ch = *pfor++)
|
||||
{
|
||||
case 'd' :
|
||||
ivalue = *parg--;
|
||||
pf_dec(ivalue);
|
||||
break;
|
||||
case 'u' :
|
||||
ivalue = *parg--;
|
||||
pf_udec(ivalue);
|
||||
break;
|
||||
case 'x' :
|
||||
ivalue = *parg--;
|
||||
pf_hex(ivalue);
|
||||
break;
|
||||
case 'c' :
|
||||
pf_cf(*parg--);
|
||||
break;
|
||||
case 's' :
|
||||
pf_sf(*parg--);
|
||||
break;
|
||||
case '\0' :
|
||||
--pfor;
|
||||
// P'abajo
|
||||
default :
|
||||
pf_out('!');
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
pf_out(ch);
|
||||
|
||||
if(xpf_err)
|
||||
break;
|
||||
}
|
||||
|
||||
pf_end();
|
||||
|
||||
return xpf_err ? -1 : xpf_cnt;
|
||||
}
|
||||
|
||||
// void pf_sf(char *s) : output formatted string.
|
||||
|
||||
pf_sf(s)
|
||||
char *s;
|
||||
{
|
||||
int len;
|
||||
char fill;
|
||||
|
||||
if(xpf_fw)
|
||||
{
|
||||
if((len = strlen(s)) < xpf_fw)
|
||||
{
|
||||
xpf_fw = xpf_fw-len;
|
||||
|
||||
if(xpf_fa)
|
||||
{
|
||||
// Left align
|
||||
fill = (xpf_fz ? '0' : ' ');
|
||||
|
||||
while(xpf_fw--)
|
||||
pf_out(fill);
|
||||
pf_s(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Right align
|
||||
pf_s(s);
|
||||
|
||||
while(xpf_fw--)
|
||||
pf_out(' ');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pf_s(s);
|
||||
}
|
||||
|
||||
// void pf_cf(char c) : output formatted character.
|
||||
|
||||
pf_cf(c)
|
||||
char c;
|
||||
{
|
||||
char tmp[2];
|
||||
|
||||
tmp[0] = c; tmp[1] = '\0';
|
||||
|
||||
pf_sf(tmp);
|
||||
}
|
||||
|
||||
unsigned char xpf_dst[7]; // Buffer for numbers
|
||||
unsigned char *xpf_dpt; // Buffer pointer
|
||||
|
||||
// void pf_dec(int i) : output signed decimal integer.
|
||||
|
||||
pf_dec(i)
|
||||
int i;
|
||||
{
|
||||
xpf_dpt = xpf_dst;
|
||||
|
||||
if(i < 0)
|
||||
{
|
||||
*xpf_dpt++ = '-'; i = -i;
|
||||
}
|
||||
|
||||
pf_dec2(i);
|
||||
|
||||
*xpf_dpt = '\0';
|
||||
|
||||
pf_sf(xpf_dst);
|
||||
}
|
||||
|
||||
// void pf_dec2(int i) : helper for pf_dec().
|
||||
|
||||
pf_dec2(i)
|
||||
int i;
|
||||
{
|
||||
int n;
|
||||
|
||||
if(n = i / 10)
|
||||
pf_dec2(n);
|
||||
|
||||
*xpf_dpt++ = i % 10 + '0';
|
||||
}
|
||||
|
||||
// void pf_udec(unsigned int i) : output unsigned decimal integer.
|
||||
|
||||
pf_udec(i)
|
||||
unsigned i;
|
||||
{
|
||||
xpf_dpt = xpf_dst;
|
||||
|
||||
pf_udec2(i);
|
||||
|
||||
*xpf_dpt = '\0';
|
||||
|
||||
pf_sf(xpf_dst);
|
||||
}
|
||||
|
||||
// void pf_udec2(unsigned int i) : helper for pf_udec().
|
||||
|
||||
pf_udec2(i)
|
||||
unsigned i;
|
||||
{
|
||||
unsigned n;
|
||||
|
||||
if(n = i / 10)
|
||||
pf_udec2(n);
|
||||
|
||||
*xpf_dpt++ = i % 10 + '0';
|
||||
}
|
||||
|
||||
// void pf_hex(unsigned int i) : output hexadecimal integer.
|
||||
|
||||
pf_hex(i)
|
||||
unsigned i;
|
||||
{
|
||||
xpf_dpt = xpf_dst;
|
||||
|
||||
pf_hex2(i);
|
||||
|
||||
*xpf_dpt = '\0';
|
||||
|
||||
pf_sf(xpf_dst);
|
||||
}
|
||||
|
||||
// void pf_hex2(unsigned int i) : helper for pf_hex().
|
||||
|
||||
pf_hex2(i)
|
||||
unsigned i;
|
||||
{
|
||||
unsigned n;
|
||||
|
||||
if(n = i / 16)
|
||||
pf_hex2(n);
|
||||
|
||||
i %= 16;
|
||||
|
||||
*xpf_dpt++ = i < 10 ? '0' + i : 'A' + i - 10;
|
||||
}
|
||||
|
||||
// void pf_s(char *s) : output string.
|
||||
|
||||
pf_s(s)
|
||||
char *s;
|
||||
{
|
||||
while(*s)
|
||||
pf_out(*s++);
|
||||
}
|
||||
|
||||
// void pf_out(char c) : output character.
|
||||
|
||||
#asm
|
||||
pf_out:
|
||||
PUSH HL
|
||||
DEFB 0CDH
|
||||
xpf_out:
|
||||
DEFW 0
|
||||
POP BC
|
||||
|
||||
EX DE,HL
|
||||
|
||||
LD HL,(xpf_cnt)
|
||||
INC HL
|
||||
LD (xpf_cnt),HL
|
||||
|
||||
LD A,D
|
||||
OR E
|
||||
RET Z
|
||||
;; LD A,255
|
||||
LD (xpf_err),A
|
||||
RET
|
||||
#endasm
|
||||
|
||||
// void pf_end(void) : end output.
|
||||
|
||||
#asm
|
||||
pf_end:
|
||||
DEFB 0C3H
|
||||
xpf_end:
|
||||
DEFW 0
|
||||
#endasm
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user