365 lines
5.4 KiB
C
365 lines
5.4 KiB
C
/**
|
||
* @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
|
||
|
||
|