1
0
Fork 0

Added Blocks

This commit is contained in:
acn 2020-03-10 15:47:00 +01:00
parent 31098a6e6b
commit 40ad25b725
15 changed files with 2997 additions and 0 deletions

BIN
Blocks/BLOCKS.COM Normal file

Binary file not shown.

BIN
Blocks/CC.COM Normal file

Binary file not shown.

BIN
Blocks/CCOPT.COM Normal file

Binary file not shown.

BIN
Blocks/HEXTOCOM.COM Normal file

Binary file not shown.

34
Blocks/README.md Normal file
View 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

Binary file not shown.

866
Blocks/blocks.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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


View File

@ -26,6 +26,7 @@ See this repository: https://git.imzadi.de/acn/backgammon-vt100
* [Cpmtris](cpmtris/)
* [Sokoban](Sokoban/)
* [Battleships](Battleships/)
* [Blocks](Blocks/)
## More Games on the Interwebs