mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2025-04-19 01:16:56 +02:00
Added formatted printing for stdio: handles everything except doubles and %m.
This commit is contained in:
parent
7f174043a5
commit
b2151886bc
40 changed files with 1496 additions and 449 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,7 +1,3 @@
|
||||||
# Sources for old gint versions.
|
|
||||||
gint.old.1/**
|
|
||||||
gint.old.2/**
|
|
||||||
|
|
||||||
# Build directory
|
# Build directory
|
||||||
build/**
|
build/**
|
||||||
|
|
||||||
|
@ -11,3 +7,6 @@ build/**
|
||||||
|
|
||||||
# Object files.
|
# Object files.
|
||||||
*.o
|
*.o
|
||||||
|
|
||||||
|
# Some notes.
|
||||||
|
LIBC
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -14,7 +14,7 @@
|
||||||
# Modules
|
# Modules
|
||||||
modules-gint = core keyboard mmu mpu rtc screen timer \
|
modules-gint = core keyboard mmu mpu rtc screen timer \
|
||||||
bopti display gray tales
|
bopti display gray tales
|
||||||
modules-libc = setjmp string
|
modules-libc = setjmp string stdio
|
||||||
|
|
||||||
# Targets
|
# Targets
|
||||||
target-g1a = gintdemo.g1a
|
target-g1a = gintdemo.g1a
|
||||||
|
@ -39,7 +39,7 @@ demo-res = $(notdir $(wildcard demo/resources/*))
|
||||||
demo-obj = $(patsubst %,build/demo_%.o,$(demo-src) $(demo-res))
|
demo-obj = $(patsubst %,build/demo_%.o,$(demo-src) $(demo-res))
|
||||||
demo-elf = build/gintdemo.elf
|
demo-elf = build/gintdemo.elf
|
||||||
demo-bin = build/gintdemo.bin
|
demo-bin = build/gintdemo.bin
|
||||||
demo-libs = -lgcc -L. -lgint -lc
|
demo-libs = -L. -lgint -lc -lgcc
|
||||||
|
|
||||||
# Specific objects
|
# Specific objects
|
||||||
obj-lib-spec = build/display_font_system.bmp.o
|
obj-lib-spec = build/display_font_system.bmp.o
|
||||||
|
|
141
Makefile.old
141
Makefile.old
|
@ -1,141 +0,0 @@
|
||||||
#! /usr/bin/make -f
|
|
||||||
|
|
||||||
#---
|
|
||||||
# fx-9860g lib Makefile.
|
|
||||||
#---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Variables and configuration.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Tools
|
|
||||||
cc = sh3eb-elf-gcc
|
|
||||||
as = sh3eb-elf-as
|
|
||||||
ar = sh3eb-elf-ar
|
|
||||||
ob = sh3eb-elf-objcopy
|
|
||||||
wr = g1a-wrapper
|
|
||||||
|
|
||||||
# Output files
|
|
||||||
g1a = ginttest.g1a
|
|
||||||
bin = build/ginttest.bin
|
|
||||||
elf = build/ginttest.elf
|
|
||||||
|
|
||||||
# Command-line options
|
|
||||||
cflags = -m3 -mb -nostdlib -ffreestanding -W -Wall \
|
|
||||||
-I . -isystem include
|
|
||||||
lib = -lgcc -L. -lgint -lc
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Source and object files.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Gint library.
|
|
||||||
src-lib = crt0.c syscalls.s \
|
|
||||||
gint.c gint_vbr.s gint_7705.c gint_7305.c \
|
|
||||||
mpu.c keyboard.c screen.c display.c gray.c timer.c tales.c \
|
|
||||||
bopti.c
|
|
||||||
hea-lib = 7305.h 7705.h gint.h \
|
|
||||||
stdlib.h \
|
|
||||||
mpu.h keyboard.h screen.h display.h gray.h timer.h tales.h
|
|
||||||
obj-lib = $(patsubst %, build/%.o, $(src-lib))
|
|
||||||
hdr-lib = $(patsubst %, include/%, $(hea-lib))
|
|
||||||
|
|
||||||
# Standard library.
|
|
||||||
src-std = setjmp.s string.c
|
|
||||||
hea-std = setjmp.h string.h ctype.h
|
|
||||||
obj-std = $(patsubst %, build/%.o, $(src-std))
|
|
||||||
hdr-std = $(patsubst %, include/%, $(hea-str))
|
|
||||||
|
|
||||||
# Test application.
|
|
||||||
src-app = ginttest.c
|
|
||||||
img-app = bitmap_opt.bmp swords.bmp sprites.bmp symbol.bmp symbol2.bmp \
|
|
||||||
illustration.bmp
|
|
||||||
res-app = $(patsubst %, build/%.o, $(img-app)) build/font.o
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Building rules.
|
|
||||||
#
|
|
||||||
|
|
||||||
all: build libgint.a libc.a ginttest.g1a
|
|
||||||
|
|
||||||
build:
|
|
||||||
mkdir -p build
|
|
||||||
|
|
||||||
libgint.a: $(obj-lib)
|
|
||||||
$(ar) rcs libgint.a $(obj-lib)
|
|
||||||
@ echo "\033[32;1mLibrary file size: "`stat -c %s libgint.a` \
|
|
||||||
"bytes\033[0m"
|
|
||||||
|
|
||||||
libc.a: $(obj-std)
|
|
||||||
$(ar) rcs libc.a $(obj-std)
|
|
||||||
@ echo "\033[32;1mStandard file size: "`stat -c %s libc.a` \
|
|
||||||
"bytes\033[0m"
|
|
||||||
|
|
||||||
$(g1a): libgint.a $(src-app) $(res-app)
|
|
||||||
$(cc) $(src-app) $(res-app) -T ginttest.ld -o $(elf) $(cflags) $(lib)
|
|
||||||
$(ob) -R .comment -R .bss -O binary $(elf) $(bin)
|
|
||||||
$(wr) $(bin) -o ginttest.g1a -i icon.bmp
|
|
||||||
@ echo "\033[32;1mBinary file size: "`stat -c %s $(bin)`" bytes\033[0m"
|
|
||||||
@ sh3eb-elf-objdump -h build/ginttest.elf
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Resource management.
|
|
||||||
#
|
|
||||||
|
|
||||||
build/%.c.o: src/%.c $(hdr-lib) $(hdr-std)
|
|
||||||
$(cc) $(cflags) -O2 -c $< -o $@
|
|
||||||
|
|
||||||
build/%.s.o: src/%.s
|
|
||||||
$(as) -c $^ -o $@
|
|
||||||
|
|
||||||
build/%.bmp.o: resources/%.bmp
|
|
||||||
fxconv $^ -o $@ --preview
|
|
||||||
|
|
||||||
build/font.o: resources/font.bmp
|
|
||||||
fxconv --font $^ -o $@
|
|
||||||
|
|
||||||
# File gint.c should not be optimized... looks like attribute((interrupt_
|
|
||||||
# handler)) doesn't like it. (It could be a gint bug also, I should check.)
|
|
||||||
build/gint.c.o: src/gint.c $(hdr-lib) $(hdr-std)
|
|
||||||
$(cc) $(cflags) -c $< -o $@
|
|
||||||
|
|
||||||
%.c.o: %.c $(hdr-lib) $(hdr-std)
|
|
||||||
$(cc) $(cflags) -c $< -o $@
|
|
||||||
%.s.o: %.s
|
|
||||||
$(as) -c $^ -o $@
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Cleaning rules.
|
|
||||||
#
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@ rm -f $(obj-lib) $(obj-std) $(obj-app) $(res-app)
|
|
||||||
@ rm -f $(bin) $(elf)
|
|
||||||
mrproper: clean
|
|
||||||
@ rm -f build/*
|
|
||||||
@ rm -f ginttest.g1a libc.a libgint.a
|
|
||||||
distclean: mrproper
|
|
||||||
|
|
||||||
re: distclean all
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Installing shorthand.
|
|
||||||
#
|
|
||||||
|
|
||||||
install:
|
|
||||||
usb-connector SEND ginttest.g1a ginttest.g1a fls0
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.PHONY: all clean mrproper distclean re install
|
|
36
README.md
36
README.md
|
@ -5,7 +5,7 @@ gint (pronounce 'guin') is a low-level library for fx-9860G calculators. It
|
||||||
provides the tools needed to develop programs under Linux using the gcc
|
provides the tools needed to develop programs under Linux using the gcc
|
||||||
toolchain (sh3eb-elf).
|
toolchain (sh3eb-elf).
|
||||||
|
|
||||||
By the way, gint is free software ; you may use it for any purpose, share it,
|
By the way, gint is free software; you may use it for any purpose, share it,
|
||||||
modify it and share you changes. No credit of any kind is needed, though
|
modify it and share you changes. No credit of any kind is needed, though
|
||||||
appreciated.
|
appreciated.
|
||||||
|
|
||||||
|
@ -15,7 +15,8 @@ Interrupt handler
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
The interrupt handler is the lowest-level part of the library. It directly
|
The interrupt handler is the lowest-level part of the library. It directly
|
||||||
accesses the peripheral modules and performs keyboard analyzes, swaps screen buffers, etc.
|
accesses the peripheral modules and performs keyboard analyzes, swaps screen
|
||||||
|
buffers, etc.
|
||||||
|
|
||||||
gint does not allow user programs to use their own handlers. However, it is
|
gint does not allow user programs to use their own handlers. However, it is
|
||||||
possible to map interrupt-driven events to user callbacks using the public API
|
possible to map interrupt-driven events to user callbacks using the public API
|
||||||
|
@ -37,11 +38,15 @@ register access and implements a few standard functions.
|
||||||
Building and installing
|
Building and installing
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
There a some dependencies:
|
||||||
|
* The `sh3eb-elf` toolchain somewhere in the PATH
|
||||||
|
* The fxSDK installed and available in the PATH
|
||||||
|
|
||||||
The easiest way to build gint is simply to enter a terminal and execute `make`.
|
The easiest way to build gint is simply to enter a terminal and execute `make`.
|
||||||
This will build the following components :
|
This will build the following components :
|
||||||
* `libgint.a`, the gint library
|
* `libgint.a`, the gint library
|
||||||
* `libc.a`, a (very) few standard procedures
|
* `libc.a`, a (very) few standard procedures
|
||||||
* `ginttest.g1a`, a test application
|
* `gintdemo.g1a`, a test application
|
||||||
|
|
||||||
The common `clean`, `mrproper`, and `distclean` rules will clean the directory.
|
The common `clean`, `mrproper`, and `distclean` rules will clean the directory.
|
||||||
|
|
||||||
|
@ -50,13 +55,18 @@ The common `clean`, `mrproper`, and `distclean` rules will clean the directory.
|
||||||
Source organization
|
Source organization
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
gint is made of *modules*. Each module has its own source directory (which is
|
gint is made of *modules*. Each module may have any of the following
|
||||||
`/src/module`), and its associated header file in `/include`. A module folder
|
components:
|
||||||
contains three types of files :
|
* A header file in `/include`
|
||||||
* Internal headers: shared only among the files of a module
|
* An internal header file in `/include/internals`
|
||||||
* Single-function source files: to avoid linking against the whole library,
|
* Single-function source files in `/src/module`: to avoid linking against the
|
||||||
some functions have their own object files. Their names are the function
|
whole library, some functions have their own object files. Their names are
|
||||||
names.
|
those of the functions.
|
||||||
* Other source files: contain multiple functions that always work together, or
|
* Other source files in `/src/module`: contain multiple functions that always
|
||||||
are lightweight enough not to be separated. Their names often begin with
|
work together, or are lightweight enough not to be separated. Their names
|
||||||
`module_`.
|
often begin with `module_`.
|
||||||
|
* Other files in `/src/module`: the `display` module contains a font, I think.
|
||||||
|
|
||||||
|
The demo application is in the `demo` directory.
|
||||||
|
|
||||||
|
The `doc` folder contains some documentation.
|
||||||
|
|
2
TODO
2
TODO
|
@ -12,6 +12,7 @@
|
||||||
@ vram overflow
|
@ vram overflow
|
||||||
@ keyboard test threaded interface
|
@ keyboard test threaded interface
|
||||||
|
|
||||||
|
+ have timers use structures from 7705.h and 7305.h
|
||||||
+ full and partial transparency
|
+ full and partial transparency
|
||||||
+ gint vs. ML with 248x124 at (-60, -28)
|
+ gint vs. ML with 248x124 at (-60, -28)
|
||||||
+ call exit handlers
|
+ call exit handlers
|
||||||
|
@ -25,7 +26,6 @@
|
||||||
+ bitmap parts
|
+ bitmap parts
|
||||||
|
|
||||||
- improve exception handler debugging information (if possible)
|
- improve exception handler debugging information (if possible)
|
||||||
- write and test gray engine
|
|
||||||
- full rtc driver (time)
|
- full rtc driver (time)
|
||||||
- callbacks and complete user API
|
- callbacks and complete user API
|
||||||
|
|
||||||
|
|
252
demo/gintdemo.c
252
demo/gintdemo.c
|
@ -9,79 +9,36 @@
|
||||||
#include <gray.h>
|
#include <gray.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <7305.h>
|
#include <7305.h>
|
||||||
|
|
||||||
|
#include <internals/stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// A few ugly procedures for displaying text. Will have to enhance this
|
// A few procedures for displaying text aligned on a 21*8 grid.
|
||||||
// soon -- which means printf().
|
// Not really beautiful... but this will do.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
void print(int x, int y, const char *format, ...)
|
||||||
|
{
|
||||||
|
if(x < 1 || x > 21 || y < 1 || y > 8) return;
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
__printf(0, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if(gray_runs()) gtext(__stdio_buffer, x * 6 - 5, y * 8 - 8);
|
||||||
|
else dtext(__stdio_buffer, x * 6 - 5, y * 8 - 8);
|
||||||
|
}
|
||||||
|
|
||||||
void locate(const char *str, int x, int y)
|
void locate(const char *str, int x, int y)
|
||||||
{
|
{
|
||||||
if(x < 1 || x > 21 || y < 1 || y > 8) return;
|
if(x < 1 || x > 21 || y < 1 || y > 8) return;
|
||||||
if(gray_runs()) gtext(str, x * 6 - 5, y * 8 - 7);
|
if(gray_runs()) gtext(str, x * 6 - 5, y * 8 - 8);
|
||||||
else dtext(str, x * 6 - 5, y * 8 - 7);
|
else dtext(str, x * 6 - 5, y * 8 - 8);
|
||||||
}
|
|
||||||
|
|
||||||
void locate_hex(unsigned int n, int x, int y)
|
|
||||||
{
|
|
||||||
char str[11] = "0x";
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
str[9 - i] = (n & 0xf) + '0' + 39 * ((n & 0xf) > 9);
|
|
||||||
n >>= 4;
|
|
||||||
}
|
|
||||||
str[10] = 0;
|
|
||||||
locate(str, x, y);
|
|
||||||
}
|
|
||||||
void locate_bin(unsigned char n, int x, int y)
|
|
||||||
{
|
|
||||||
char str[9];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < 8;i ++)
|
|
||||||
{
|
|
||||||
str[7 - i] = (n & 1) + '0';
|
|
||||||
n >>= 1;
|
|
||||||
}
|
|
||||||
str[8] = 0;
|
|
||||||
locate(str, x, y);
|
|
||||||
}
|
|
||||||
void locate_hexa(unsigned int n, int digits, int x, int y)
|
|
||||||
{
|
|
||||||
char str[20];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = digits - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
str[i] = (n & 0xf) + '0' + 39 * ((n & 0xf) > 9);
|
|
||||||
n >>= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
str[digits] = 0;
|
|
||||||
locate(str, x, y);
|
|
||||||
}
|
|
||||||
void locate_int(int n, int x, int y)
|
|
||||||
{
|
|
||||||
char str[20] = { 0 };
|
|
||||||
int i, o = 0;
|
|
||||||
int digits = 0, copy = n;
|
|
||||||
|
|
||||||
if(!n) { str[o++] = '0'; locate(str, x, y); return; }
|
|
||||||
if(n < 0) str[o++] = '-', n = -n;
|
|
||||||
while(copy) digits++, copy /= 10;
|
|
||||||
|
|
||||||
for(i = 0; i < digits; i++)
|
|
||||||
{
|
|
||||||
str[o + digits - i - 1] = n % 10 + '0';
|
|
||||||
n /= 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
locate(str, x, y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,6 +47,26 @@ void locate_int(int n, int x, int y)
|
||||||
// Test applications.
|
// Test applications.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
keyboard_test_binary()
|
||||||
|
Prints a byte as binary/
|
||||||
|
*/
|
||||||
|
void keyboard_test_binary(int byte, int x, int y)
|
||||||
|
{
|
||||||
|
char str[9];
|
||||||
|
int i = 7;
|
||||||
|
|
||||||
|
str[8] = 0;
|
||||||
|
while(i >= 0)
|
||||||
|
{
|
||||||
|
str[i] = '0' + (byte & 1);
|
||||||
|
byte >>= 1;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
locate(str, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
keyboard_test_timer()
|
keyboard_test_timer()
|
||||||
Displays a keyboard test. The keyboard state is displayed as well, but
|
Displays a keyboard test. The keyboard state is displayed as well, but
|
||||||
|
@ -103,17 +80,17 @@ void keyboard_test_timer(void)
|
||||||
|
|
||||||
dclear_area(5, 10, 71, 34);
|
dclear_area(5, 10, 71, 34);
|
||||||
|
|
||||||
locate_bin(state[0], 5, 10);
|
keyboard_test_binary(state[0], 1, 1);
|
||||||
locate_bin(state[1], 5, 16);
|
keyboard_test_binary(state[1], 1, 2);
|
||||||
locate_bin(state[2], 5, 22);
|
keyboard_test_binary(state[2], 1, 3);
|
||||||
locate_bin(state[3], 5, 28);
|
keyboard_test_binary(state[3], 1, 4);
|
||||||
locate_bin(state[4], 5, 34);
|
keyboard_test_binary(state[4], 1, 5);
|
||||||
|
|
||||||
locate_bin(state[5], 40, 10);
|
keyboard_test_binary(state[5], 10, 1);
|
||||||
locate_bin(state[6], 40, 16);
|
keyboard_test_binary(state[6], 10, 2);
|
||||||
locate_bin(state[7], 40, 22);
|
keyboard_test_binary(state[7], 10, 3);
|
||||||
locate_bin(state[8], 40, 28);
|
keyboard_test_binary(state[8], 10, 4);
|
||||||
locate_bin(state[9], 40, 34);
|
keyboard_test_binary(state[9], 10, 5);
|
||||||
|
|
||||||
dupdate();
|
dupdate();
|
||||||
}
|
}
|
||||||
|
@ -304,10 +281,10 @@ void gray_test(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
locate("light", 15, 2);
|
locate("light", 15, 2);
|
||||||
locate_int(delays[0], 15, 3);
|
print(15, 3, "%d", delays[0]);
|
||||||
|
|
||||||
locate("dark", 15, 5);
|
locate("dark", 15, 5);
|
||||||
locate_int(delays[1], 15, 6);
|
print(15, 6, "%d", delays[1]);
|
||||||
|
|
||||||
locate("\x02", 14, selected ? 6 : 3);
|
locate("\x02", 14, selected ? 6 : 3);
|
||||||
|
|
||||||
|
@ -328,7 +305,7 @@ void gray_test(void)
|
||||||
selected = !selected;
|
selected = !selected;
|
||||||
break;
|
break;
|
||||||
case KEY_F2:
|
case KEY_F2:
|
||||||
delays[0] = 993;
|
delays[0] = isSH3() ? 985 : 994;
|
||||||
delays[1] = 1609;
|
delays[1] = 1609;
|
||||||
break;
|
break;
|
||||||
case KEY_F3:
|
case KEY_F3:
|
||||||
|
@ -356,6 +333,25 @@ void gray_test(void)
|
||||||
gray_stop();
|
gray_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
printf_test()
|
||||||
|
Tests formatting functions.
|
||||||
|
*/
|
||||||
|
void printf_test(void)
|
||||||
|
{
|
||||||
|
dclear();
|
||||||
|
locate("Formatted printing", 1, 1);
|
||||||
|
|
||||||
|
print(2, 3, "%%4.2d 5 :\"%4.2d\"", 5);
|
||||||
|
print(2, 4, "%%-3c '&':\"%-3c\"", '&');
|
||||||
|
print(2, 5, "%%#05x 27 :\"%#05x\"", 27);
|
||||||
|
print(2, 6, "%%1s \"tr\":\"%1s\"", "tr");
|
||||||
|
print(2, 7, "%%6p NULL :\"%7p\"", NULL);
|
||||||
|
|
||||||
|
dupdate();
|
||||||
|
while(getkey() != KEY_EXIT);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static const unsigned char screen[1024] = {
|
static const unsigned char screen[1024] = {
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
@ -537,12 +533,8 @@ void tlb_debug(void)
|
||||||
{
|
{
|
||||||
dclear();
|
dclear();
|
||||||
|
|
||||||
locate("TLB", 1, 1);
|
print(1, 1, "TLB way=%d %d-%d", way, entry,
|
||||||
locate("way=", 8, 1);
|
entry > 29 ? 31 : entry + 2);
|
||||||
locate("0\0001\0002\0003" + (way << 1), 12, 1);
|
|
||||||
locate_int(entry, 16 + (entry < 10), 1);
|
|
||||||
locate("-", 18, 1);
|
|
||||||
locate_int((entry + 2 > 31) ? (31) : (entry + 2) , 19, 1);
|
|
||||||
|
|
||||||
for(i = 0; i < 3 && entry < 32; i++, entry++)
|
for(i = 0; i < 3 && entry < 32; i++, entry++)
|
||||||
{
|
{
|
||||||
|
@ -567,14 +559,11 @@ void tlb_debug(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
r = 2 * i + 3;
|
r = 2 * i + 3;
|
||||||
locate_hexa(pointer_base, 8, 1, r);
|
print(1, r, "%08x :%08x", pointer_base, ppn << 10);
|
||||||
locate(":", 11, r);
|
|
||||||
locate_hexa(ppn << 10, 8, 12, r);
|
|
||||||
|
|
||||||
r++;
|
r++;
|
||||||
locate((d & 0x08) ? "4k" : "1k", 1, r);
|
locate((d & 0x08) ? "4k" : "1k", 1, r);
|
||||||
locate("pr=", 5, r);
|
print(5, r, "pr=%s", protection[(d >> 5) & 3]);
|
||||||
locate(protection[(d >> 5) & 3], 8, r);
|
|
||||||
locate((d & 0x02) ? "shared" : "exclusive", 13, r);
|
locate((d & 0x02) ? "shared" : "exclusive", 13, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,6 +603,7 @@ void main_menu(int *category, int *app)
|
||||||
"Image rendering",
|
"Image rendering",
|
||||||
"Text rendering",
|
"Text rendering",
|
||||||
"Real-time clock",
|
"Real-time clock",
|
||||||
|
"Text formatting",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
const char *list_perfs[] = {
|
const char *list_perfs[] = {
|
||||||
|
@ -626,14 +616,15 @@ void main_menu(int *category, int *app)
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
const char **list;
|
const char **list;
|
||||||
|
int list_len;
|
||||||
|
|
||||||
extern unsigned int bgint, egint;
|
extern unsigned int bgint, egint;
|
||||||
extern unsigned int romdata;
|
extern unsigned int romdata;
|
||||||
int gint_size = &egint - &bgint;
|
int gint_size = (char *)&egint - (char *)&bgint;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int tab = 0, index = 0;
|
static int tab = 0, index = 0, scroll = 0;
|
||||||
// Set to 1 when interface has to be redrawn.
|
// Set to 1 when interface has to be redrawn.
|
||||||
int leave = 1;
|
int leave = 1;
|
||||||
int i;
|
int i;
|
||||||
|
@ -654,14 +645,10 @@ void main_menu(int *category, int *app)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
locate("Demo application", 1, 1);
|
locate("Demo application", 1, 1);
|
||||||
locate("gint version:", 2, 3);
|
print(2, 3, "gint version: %5s", GINT_VERSION_STR);
|
||||||
locate(GINT_VERSION_STR, 16, 3);
|
print(2, 4, "handler size: %5d", gint_size);
|
||||||
locate("handler size:", 2, 4);
|
print(2, 5, "mpu type: %7s", mpu);
|
||||||
locate_int(gint_size, (gint_size < 1000 ? 18 : 17), 4);
|
print(2, 6, "romdata: %08x", &romdata);
|
||||||
locate("mpu type:", 2, 5);
|
|
||||||
locate(mpu, 21 - strlen(mpu), 5);
|
|
||||||
locate("romdata:", 2, 6);
|
|
||||||
locate_hex((unsigned int)&romdata, 11, 6);
|
|
||||||
|
|
||||||
list = NULL;
|
list = NULL;
|
||||||
break;
|
break;
|
||||||
|
@ -682,16 +669,24 @@ void main_menu(int *category, int *app)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
locate("Tab ", 1, 1);
|
print(1, 1, "Tab %d", tab);
|
||||||
locate_int(tab, 5, 1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dimage(&res_opt_menu_start, 0, 56);
|
dimage(&res_opt_menu_start, 0, 56);
|
||||||
|
|
||||||
if(list)
|
if(list)
|
||||||
{
|
{
|
||||||
for(i = 0; list[i]; i++) locate(list[i], 2, i + 2);
|
list_len = 0;
|
||||||
dreverse_area(0, 8 * index + 9, 127, 8 * index + 16);
|
while(list[list_len]) list_len++;
|
||||||
|
|
||||||
|
for(i = scroll; list[i] && i < scroll + 6; i++)
|
||||||
|
locate(list[i], 2, i - scroll + 2);
|
||||||
|
|
||||||
|
if(scroll > 0) locate("\x0d", 20, 2);
|
||||||
|
if(scroll + 6 < list_len) locate("\x0e", 20, 7);
|
||||||
|
|
||||||
|
dreverse_area(0, 8 * (index - scroll) + 8, 127,
|
||||||
|
8 * (index - scroll) + 15);
|
||||||
}
|
}
|
||||||
dupdate();
|
dupdate();
|
||||||
|
|
||||||
|
@ -706,27 +701,58 @@ void main_menu(int *category, int *app)
|
||||||
switch(getkey())
|
switch(getkey())
|
||||||
{
|
{
|
||||||
case KEY_F1:
|
case KEY_F1:
|
||||||
tab = 0;
|
tab = 0;
|
||||||
index = 0;
|
index = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_F2:
|
case KEY_F2:
|
||||||
tab = 1;
|
tab = 1;
|
||||||
index = 0;
|
index = 0;
|
||||||
|
scroll = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_F3:
|
case KEY_F3:
|
||||||
tab = 2;
|
tab = 2;
|
||||||
index = 0;
|
index = 0;
|
||||||
|
scroll = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_F4:
|
case KEY_F4:
|
||||||
tab = 3;
|
tab = 3;
|
||||||
index = 0;
|
index = 0;
|
||||||
|
scroll = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_UP:
|
case KEY_UP:
|
||||||
if(list && index) index--;
|
if(list && list_len > 1)
|
||||||
|
{
|
||||||
|
if(index)
|
||||||
|
{
|
||||||
|
index--;
|
||||||
|
if(index < scroll) scroll--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = list_len - 1;
|
||||||
|
scroll = list_len - 6;
|
||||||
|
if(scroll < 0) scroll = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else leave = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_DOWN:
|
case KEY_DOWN:
|
||||||
if(list && list[index + 1]) index++;
|
if(list && list_len > 1)
|
||||||
|
{
|
||||||
|
if(list[index + 1])
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
if(index >= scroll + 6)
|
||||||
|
scroll++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = 0;
|
||||||
|
scroll = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else leave = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_EXE:
|
case KEY_EXE:
|
||||||
|
@ -735,7 +761,6 @@ void main_menu(int *category, int *app)
|
||||||
if(app) *app = index + 1;
|
if(app) *app = index + 1;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case KEY_EXIT:
|
|
||||||
case KEY_MENU:
|
case KEY_MENU:
|
||||||
if(category) *category = 0;
|
if(category) *category = 0;
|
||||||
if(app) *app = 0;
|
if(app) *app = 0;
|
||||||
|
@ -783,6 +808,9 @@ int main(void)
|
||||||
case 0x0105:
|
case 0x0105:
|
||||||
// rtc_test();
|
// rtc_test();
|
||||||
break;
|
break;
|
||||||
|
case 0x0106:
|
||||||
|
printf_test();
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x0301:
|
case 0x0301:
|
||||||
if(isSH3()) tlb_debug();
|
if(isSH3()) tlb_debug();
|
||||||
|
|
17
doc/bopti.md
17
doc/bopti.md
|
@ -38,7 +38,8 @@ bitwise instructions, so that performance is maintained.
|
||||||
|
|
||||||
Consider for instance a logical and operation (`(a, b) -> a & b`).
|
Consider for instance a logical and operation (`(a, b) -> a & b`).
|
||||||
Operating on pixels would need to move some data, test the value of a bit in
|
Operating on pixels would need to move some data, test the value of a bit in
|
||||||
the mask, edit the vram data, and eventually shift both the data and the mask, for all of the 32 pixels.
|
the mask, edit the vram data, and eventually shift both the data and the mask,
|
||||||
|
for all of the 32 pixels.
|
||||||
One could not expect this from happening in less than 150 processor cycles
|
One could not expect this from happening in less than 150 processor cycles
|
||||||
(in comparison, using generic-purpose `setPixel()`-like functions would be at
|
(in comparison, using generic-purpose `setPixel()`-like functions would be at
|
||||||
least 10 times as long). The smarter method operates directly on the longword
|
least 10 times as long). The smarter method operates directly on the longword
|
||||||
|
@ -76,10 +77,9 @@ operations that correspond to the kind of image.
|
||||||
|
|
||||||
*Detailed article: [Gray engine](gray-engine)*
|
*Detailed article: [Gray engine](gray-engine)*
|
||||||
|
|
||||||
Gray pixels are made of one four colors, each of which is represented by two
|
Gray pixels are made of four colors represented by pairs of bits. Arguments
|
||||||
bits. Arguments `light` and `dark` of gray operation functions are longwords
|
`light` and `dark` of gray operation functions are longwords containing the
|
||||||
containing the least significant and most significant of these bits,
|
least significant and most significant of these bits, respectively.
|
||||||
respectively.
|
|
||||||
|
|
||||||
white = 0 [00]
|
white = 0 [00]
|
||||||
lightgray = 1 [01]
|
lightgray = 1 [01]
|
||||||
|
@ -168,7 +168,7 @@ darken(light, dark, x) = (light | (dark & x), (light & x) | (x ^ dark))
|
||||||
darken2(light, dark, x) = (light | x, (light & x) | dark)
|
darken2(light, dark, x) = (light | x, (light & x) | dark)
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
One could easily check that these functions do their jobs when `x = 1` and
|
One could easily check that these functions do their jobs when `x = 1` and
|
||||||
leave the data unchanged when `x = 0`.
|
leave the data unchanged when `x = 0`.
|
||||||
|
|
||||||
|
|
||||||
|
@ -183,7 +183,8 @@ Images are made of *layers*, each of which describe the mask for an operation.
|
||||||
When an image is rendered, *bopti* draws some of those layers in the vram
|
When an image is rendered, *bopti* draws some of those layers in the vram
|
||||||
using the operation functions.
|
using the operation functions.
|
||||||
|
|
||||||
* Non-transparent monochrome images only have one layer, which describes the mask for the `draw` operation.
|
* Non-transparent monochrome images only have one layer, which describes the
|
||||||
|
mask for the `draw` operation.
|
||||||
* Transparent monochrome images have two layers. The first describes the mask
|
* Transparent monochrome images have two layers. The first describes the mask
|
||||||
for the `draw` operation, while the other is the `alpha` operation mask (which
|
for the `draw` operation, while the other is the `alpha` operation mask (which
|
||||||
means that it indicates which pixels are transparent).
|
means that it indicates which pixels are transparent).
|
||||||
|
@ -199,7 +200,7 @@ transparent), and the third indicates the color.
|
||||||
Layers are encoded as a bit map. The image is split into a *grid*, which is
|
Layers are encoded as a bit map. The image is split into a *grid*, which is
|
||||||
made of 32-pixel *columns*, and an *end*.
|
made of 32-pixel *columns*, and an *end*.
|
||||||
|
|
||||||
32 32 32 e
|
32 32 32 end
|
||||||
+------+------+------+---+
|
+------+------+------+---+
|
||||||
| | | | |
|
| | | | |
|
||||||
| | | | |
|
| | | | |
|
||||||
|
|
BIN
gintdemo.g1a
BIN
gintdemo.g1a
Binary file not shown.
|
@ -5,7 +5,8 @@
|
||||||
Double-underscore prefixed structures (e.g. __st_rtc_counter) are used
|
Double-underscore prefixed structures (e.g. __st_rtc_counter) are used
|
||||||
internally but are not meant to be used in user programs.
|
internally but are not meant to be used in user programs.
|
||||||
|
|
||||||
Underscore-prefixed names (e.g. _R64CNT) indicate write-only registers.
|
Underscore-prefixed names (e.g. _R64CNT) are used to avoid name
|
||||||
|
conflicts (e.g. STRUCTURE.RTC would expand to STRUCTURE.((T *)0x...)).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
@ -20,7 +21,6 @@
|
||||||
struct _st_rtc
|
struct _st_rtc
|
||||||
{
|
{
|
||||||
unsigned char const R64CNT;
|
unsigned char const R64CNT;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -31,7 +31,6 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RSECCNT;
|
} RSECCNT;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -42,7 +41,6 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RMINCNT;
|
} RMINCNT;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -53,12 +51,10 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RHRCNT;
|
} RHRCNT;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
// 0=Sunday, 1=Monday, ..., 6=Saturday, 7=Reserved (prohibited).
|
// 0=Sunday, 1=Monday, ..., 6=Saturday, 7=Reserved (prohibited).
|
||||||
unsigned char RWKCNT;
|
unsigned char RWKCNT;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -69,7 +65,6 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RDAYCNT;
|
} RDAYCNT;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -80,7 +75,6 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RMONCNT;
|
} RMONCNT;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -101,7 +95,6 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RSECAR;
|
} RSECAR;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -112,7 +105,6 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RMINAR;
|
} RMINAR;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -124,7 +116,6 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RHRAR;
|
} RHRAR;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -136,7 +127,6 @@ struct _st_rtc
|
||||||
unsigned DAY :3;
|
unsigned DAY :3;
|
||||||
};
|
};
|
||||||
} RWKAR;
|
} RWKAR;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -148,7 +138,6 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RDAYAR;
|
} RDAYAR;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -160,7 +149,6 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RMONAR;
|
} RMONAR;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -174,7 +162,6 @@ struct _st_rtc
|
||||||
unsigned AF :1;
|
unsigned AF :1;
|
||||||
};
|
};
|
||||||
} RCR1;
|
} RCR1;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -188,7 +175,6 @@ struct _st_rtc
|
||||||
unsigned START :1;
|
unsigned START :1;
|
||||||
};
|
};
|
||||||
} RCR2;
|
} RCR2;
|
||||||
|
|
||||||
gap(1);
|
gap(1);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -200,7 +186,6 @@ struct _st_rtc
|
||||||
unsigned ONES :4;
|
unsigned ONES :4;
|
||||||
};
|
};
|
||||||
} RYRAR;
|
} RYRAR;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -357,7 +342,6 @@ struct _st_intx
|
||||||
unsigned IrDA :4;
|
unsigned IrDA :4;
|
||||||
};
|
};
|
||||||
} IPRA;
|
} IPRA;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -369,7 +353,6 @@ struct _st_intx
|
||||||
unsigned BEU2_1 :4;
|
unsigned BEU2_1 :4;
|
||||||
};
|
};
|
||||||
} IPRB;
|
} IPRB;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -381,7 +364,6 @@ struct _st_intx
|
||||||
unsigned SPU :4;
|
unsigned SPU :4;
|
||||||
};
|
};
|
||||||
} IPRC;
|
} IPRC;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -393,7 +375,6 @@ struct _st_intx
|
||||||
unsigned ATAPI :4;
|
unsigned ATAPI :4;
|
||||||
};
|
};
|
||||||
} IPRD;
|
} IPRD;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -405,19 +386,17 @@ struct _st_intx
|
||||||
unsigned VPU5F :4;
|
unsigned VPU5F :4;
|
||||||
};
|
};
|
||||||
} IPRE;
|
} IPRE;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
unsigned short WORD;
|
unsigned short WORD;
|
||||||
struct {
|
struct {
|
||||||
unsigned KEYSC :4;
|
unsigned _KEYSC :4;
|
||||||
unsigned DMAC0B :4;
|
unsigned DMAC0B :4;
|
||||||
unsigned USB01 :4;
|
unsigned USB01 :4;
|
||||||
unsigned CMT :4;
|
unsigned CMT :4;
|
||||||
};
|
};
|
||||||
} IPRF;
|
} IPRF;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -429,7 +408,6 @@ struct _st_intx
|
||||||
unsigned VEU3F0 :4;
|
unsigned VEU3F0 :4;
|
||||||
};
|
};
|
||||||
} IPRG;
|
} IPRG;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -441,7 +419,6 @@ struct _st_intx
|
||||||
unsigned I2C0 :4;
|
unsigned I2C0 :4;
|
||||||
};
|
};
|
||||||
} IPRH;
|
} IPRH;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -453,7 +430,6 @@ struct _st_intx
|
||||||
unsigned _2DG_ICB :4;
|
unsigned _2DG_ICB :4;
|
||||||
};
|
};
|
||||||
} IPRI;
|
} IPRI;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -465,7 +441,6 @@ struct _st_intx
|
||||||
unsigned SDHI1 :4;
|
unsigned SDHI1 :4;
|
||||||
};
|
};
|
||||||
} IPRJ;
|
} IPRJ;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -477,7 +452,6 @@ struct _st_intx
|
||||||
unsigned SDHI0 :4;
|
unsigned SDHI0 :4;
|
||||||
};
|
};
|
||||||
} IPRK;
|
} IPRK;
|
||||||
|
|
||||||
gap(2);
|
gap(2);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -489,7 +463,6 @@ struct _st_intx
|
||||||
unsigned _2DDMAC :4;
|
unsigned _2DDMAC :4;
|
||||||
};
|
};
|
||||||
} IPRL;
|
} IPRL;
|
||||||
|
|
||||||
char gap1[82];
|
char gap1[82];
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -506,7 +479,6 @@ struct _st_intx
|
||||||
unsigned SDHII0 :1;
|
unsigned SDHII0 :1;
|
||||||
};
|
};
|
||||||
} IMR0;
|
} IMR0;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -523,7 +495,6 @@ struct _st_intx
|
||||||
unsigned DEI0 :1;
|
unsigned DEI0 :1;
|
||||||
};
|
};
|
||||||
} IMR1;
|
} IMR1;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -538,7 +509,6 @@ struct _st_intx
|
||||||
unsigned SCIFA0 :1;
|
unsigned SCIFA0 :1;
|
||||||
};
|
};
|
||||||
} IMR2;
|
} IMR2;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -553,7 +523,6 @@ struct _st_intx
|
||||||
unsigned IRDAI :1;
|
unsigned IRDAI :1;
|
||||||
};
|
};
|
||||||
} IMR3;
|
} IMR3;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -569,7 +538,6 @@ struct _st_intx
|
||||||
unsigned LCDCI :1;
|
unsigned LCDCI :1;
|
||||||
};
|
};
|
||||||
} IMR4;
|
} IMR4;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -586,7 +554,6 @@ struct _st_intx
|
||||||
unsigned SCIF0 :1;
|
unsigned SCIF0 :1;
|
||||||
};
|
};
|
||||||
} IMR5;
|
} IMR5;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -602,7 +569,6 @@ struct _st_intx
|
||||||
unsigned MSIOFI1 :1;
|
unsigned MSIOFI1 :1;
|
||||||
};
|
};
|
||||||
} IMR6;
|
} IMR6;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -619,7 +585,6 @@ struct _st_intx
|
||||||
unsigned AL1I :1;
|
unsigned AL1I :1;
|
||||||
};
|
};
|
||||||
} IMR7;
|
} IMR7;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -635,7 +600,6 @@ struct _st_intx
|
||||||
unsigned FSI :1;
|
unsigned FSI :1;
|
||||||
};
|
};
|
||||||
} IMR8;
|
} IMR8;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -650,7 +614,6 @@ struct _st_intx
|
||||||
unsigned :1;
|
unsigned :1;
|
||||||
};
|
};
|
||||||
} IMR9;
|
} IMR9;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -667,7 +630,6 @@ struct _st_intx
|
||||||
unsigned CUI :1;
|
unsigned CUI :1;
|
||||||
};
|
};
|
||||||
} IMR10;
|
} IMR10;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -684,7 +646,6 @@ struct _st_intx
|
||||||
unsigned TSIFI :1;
|
unsigned TSIFI :1;
|
||||||
};
|
};
|
||||||
} IMR11;
|
} IMR11;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -695,7 +656,6 @@ struct _st_intx
|
||||||
unsigned _2DDMAC :1;
|
unsigned _2DDMAC :1;
|
||||||
};
|
};
|
||||||
} IMR12;
|
} IMR12;
|
||||||
|
|
||||||
char gap2[15];
|
char gap2[15];
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -712,7 +672,6 @@ struct _st_intx
|
||||||
unsigned SDHII0 :1;
|
unsigned SDHII0 :1;
|
||||||
};
|
};
|
||||||
} _IMCR0;
|
} _IMCR0;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -729,7 +688,6 @@ struct _st_intx
|
||||||
unsigned DEI0 :1;
|
unsigned DEI0 :1;
|
||||||
};
|
};
|
||||||
} _IMCR1;
|
} _IMCR1;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -744,7 +702,6 @@ struct _st_intx
|
||||||
unsigned SCIFA0 :1;
|
unsigned SCIFA0 :1;
|
||||||
};
|
};
|
||||||
} _IMCR2;
|
} _IMCR2;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -759,7 +716,6 @@ struct _st_intx
|
||||||
unsigned IRDAI :1;
|
unsigned IRDAI :1;
|
||||||
};
|
};
|
||||||
} _IMCR3;
|
} _IMCR3;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -775,7 +731,6 @@ struct _st_intx
|
||||||
unsigned LCDCI :1;
|
unsigned LCDCI :1;
|
||||||
};
|
};
|
||||||
} _IMCR4;
|
} _IMCR4;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -792,7 +747,6 @@ struct _st_intx
|
||||||
unsigned SCIF0 :1;
|
unsigned SCIF0 :1;
|
||||||
};
|
};
|
||||||
} _IMCR5;
|
} _IMCR5;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -808,7 +762,6 @@ struct _st_intx
|
||||||
unsigned MSIOFI1 :1;
|
unsigned MSIOFI1 :1;
|
||||||
};
|
};
|
||||||
} _IMCR6;
|
} _IMCR6;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -825,7 +778,6 @@ struct _st_intx
|
||||||
unsigned AL1I :1;
|
unsigned AL1I :1;
|
||||||
};
|
};
|
||||||
} _IMCR7;
|
} _IMCR7;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -841,7 +793,6 @@ struct _st_intx
|
||||||
unsigned FSI :1;
|
unsigned FSI :1;
|
||||||
};
|
};
|
||||||
} _IMCR8;
|
} _IMCR8;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -856,7 +807,6 @@ struct _st_intx
|
||||||
unsigned :1;
|
unsigned :1;
|
||||||
};
|
};
|
||||||
} _IMCR9;
|
} _IMCR9;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -873,7 +823,6 @@ struct _st_intx
|
||||||
unsigned CUI :1;
|
unsigned CUI :1;
|
||||||
};
|
};
|
||||||
} _IMCR10;
|
} _IMCR10;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
@ -890,7 +839,6 @@ struct _st_intx
|
||||||
unsigned TSIFI :1;
|
unsigned TSIFI :1;
|
||||||
};
|
};
|
||||||
} _IMCR11;
|
} _IMCR11;
|
||||||
|
|
||||||
gap(3);
|
gap(3);
|
||||||
|
|
||||||
union
|
union
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//---
|
//---
|
||||||
//
|
//
|
||||||
// gint core module: alloca
|
// standard library module: alloca
|
||||||
//
|
//
|
||||||
// Allows dynamic memory allocation on the stack. Memory is automatically
|
// Allows dynamic memory allocation on the stack. Memory is automatically
|
||||||
// freed when the calling function exits.
|
// freed when the calling function exits.
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// standard library module: ctype
|
||||||
|
//
|
||||||
|
// Some character manipulation.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
#ifndef _CTYPE_H
|
#ifndef _CTYPE_H
|
||||||
#define _CTYPE_H 1
|
#define _CTYPE_H 1
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,7 @@
|
||||||
// Heading declarations.
|
// Heading declarations.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <internals/tales.h>
|
||||||
#include <tales.h>
|
|
||||||
|
|
||||||
enum Color
|
enum Color
|
||||||
{
|
{
|
||||||
|
@ -149,47 +148,4 @@ void dline(int x1, int y1, int x2, int y2, enum Color color);
|
||||||
*/
|
*/
|
||||||
void dimage(struct Image *image, int x, int y);
|
void dimage(struct Image *image, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
|
||||||
// Rectangle masks.
|
|
||||||
//
|
|
||||||
// The concept of 'rectangle masks' is used several times in this module.
|
|
||||||
// It is based on the fact that an operation that affects a rectangle acts
|
|
||||||
// the same on all its lines. Therefore the behavior of the operation is
|
|
||||||
// determined by its behavior on a single line, which is represented using
|
|
||||||
// 'masks' whose bits indicate whether a pixel is affected (1) or not (0).
|
|
||||||
//
|
|
||||||
// For example when clearing the screen rectangle (16, 16, 112, 48), the
|
|
||||||
// masks will represent information '16 to 112 on x-axis', and will hold
|
|
||||||
// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These
|
|
||||||
// masks can then be used by setting vram[offset] &= ~masks[i]. This
|
|
||||||
// appears to be very flexible : for instance, vram[offset] ^= masks[i]
|
|
||||||
// will reverse the pixels in the same rectangle.
|
|
||||||
//
|
|
||||||
// This technique can also be used in more subtle cases with more complex
|
|
||||||
// patterns, but within this module it is unlikely to happen.
|
|
||||||
//
|
|
||||||
//---
|
|
||||||
|
|
||||||
/*
|
|
||||||
adjustRectangle()
|
|
||||||
Adjusts the given rectangle coordinates to ensure that :
|
|
||||||
- the rectangle is entirely contained in the screen
|
|
||||||
- x1 < x2
|
|
||||||
- y1 < y2
|
|
||||||
which is needed when working with screen rectangles.
|
|
||||||
*/
|
|
||||||
void adjustRectangle(int *x1, int *y1, int *x2, int *y2);
|
|
||||||
|
|
||||||
/*
|
|
||||||
getMasks()
|
|
||||||
Computes the rectangle masks needed to affect pixels located between x1
|
|
||||||
and x2 (both included). The four masks are stored in the third argument
|
|
||||||
(seen as an array).
|
|
||||||
*/
|
|
||||||
void getMasks(int x1, int x2, uint32_t *masks);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _DISPLAY_H
|
#endif // _DISPLAY_H
|
||||||
|
|
|
@ -32,6 +32,45 @@ unsigned int gint_systemVBR(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Register access.
|
||||||
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
enum Register
|
||||||
|
Represents common registers. Used as identifiers to retrieve their
|
||||||
|
values using gint_register().
|
||||||
|
*/
|
||||||
|
enum Register
|
||||||
|
{
|
||||||
|
Register_EXPEVT,
|
||||||
|
Register_MMUCR,
|
||||||
|
Register_TEA,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
gint_register()
|
||||||
|
Returns the address of a common register. All common registers exist
|
||||||
|
on both platforms but they may hold different values for the same
|
||||||
|
information (f.i. EXPEVT may not return the same value for a given
|
||||||
|
exception on both 7705 and 7305).
|
||||||
|
*/
|
||||||
|
volatile void *gint_reg(enum Register reg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gint_strerror()
|
||||||
|
Returns a string that describe the error set in EXPEVT in case of
|
||||||
|
general exception of TLB miss exception. This string is platform-
|
||||||
|
independent.
|
||||||
|
Some exception codes represent different errors when invoked inside the
|
||||||
|
general exception handler and the TLB error handler. Parameter 'is_tlb'
|
||||||
|
should be set to zero for general exception meanings, and anything non-
|
||||||
|
zero for TLB error meanings.
|
||||||
|
*/
|
||||||
|
const char *gint_strerror(int is_tlb);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Internal API.
|
// Internal API.
|
||||||
// Referenced here for documentation purposes only.
|
// Referenced here for documentation purposes only.
|
||||||
|
@ -75,6 +114,15 @@ void gint_setup_7305(void);
|
||||||
void gint_stop_7705(void);
|
void gint_stop_7705(void);
|
||||||
void gint_stop_7305(void);
|
void gint_stop_7305(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gint_reg()
|
||||||
|
gint_strerror()
|
||||||
|
See "Register access" section.
|
||||||
|
*/
|
||||||
|
volatile void *gint_reg_7705(enum Register reg);
|
||||||
|
volatile void *gint_reg_7305(enum Register reg);
|
||||||
|
const char *gint_strerror_7705(int is_tlb);
|
||||||
|
const char *gint_strerror_7305(int is_tlb);
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
|
@ -110,49 +158,6 @@ void gint_int_7305(void) __attribute__((section(".gint.int")));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
|
||||||
// Register access.
|
|
||||||
//---
|
|
||||||
|
|
||||||
/*
|
|
||||||
enum Register
|
|
||||||
Represents common registers. Used as identifiers to retrieve their
|
|
||||||
values using gint_register().
|
|
||||||
*/
|
|
||||||
enum Register
|
|
||||||
{
|
|
||||||
Register_EXPEVT,
|
|
||||||
Register_MMUCR,
|
|
||||||
Register_TEA,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
gint_register()
|
|
||||||
Returns the address of a common register. All common registers exist
|
|
||||||
on both platforms but they may hold different values for the same
|
|
||||||
information (f.i. EXPEVT may not return the same value for a given
|
|
||||||
exception on both 7705 and 7305).
|
|
||||||
*/
|
|
||||||
volatile void *gint_reg(enum Register reg);
|
|
||||||
volatile void *gint_reg_7705(enum Register reg);
|
|
||||||
volatile void *gint_reg_7305(enum Register reg);
|
|
||||||
|
|
||||||
/*
|
|
||||||
gint_strerror()
|
|
||||||
Returns a string that describe the error set in EXPEVT in case of
|
|
||||||
general exception of TLB miss exception. This string is platform-
|
|
||||||
independent.
|
|
||||||
Some exception codes represent different errors when invoked inside the
|
|
||||||
general exception handler and the TLB error handler. Parameter 'is_tlb'
|
|
||||||
should be set to zero for general exception meanings, and anything non-
|
|
||||||
zero for TLB error meanings.
|
|
||||||
*/
|
|
||||||
const char *gint_strerror(int is_tlb);
|
|
||||||
const char *gint_strerror_7705(int is_tlb);
|
|
||||||
const char *gint_strerror_7305(int is_tlb);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Internal platform-independent definitions.
|
// Internal platform-independent definitions.
|
||||||
//---
|
//---
|
||||||
|
|
|
@ -86,7 +86,7 @@ struct Command
|
||||||
// The video ram addresses are set by the public functions and used internally
|
// The video ram addresses are set by the public functions and used internally
|
||||||
// by the module.
|
// by the module.
|
||||||
// Monochrome video ram, light and dark buffers (in this order).
|
// Monochrome video ram, light and dark buffers (in this order).
|
||||||
extern int *vram, *v1, *v2;
|
extern int *bopti_vram, *bopti_v1, *bopti_v2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,47 @@
|
||||||
#ifndef _INTERNALS_DISPLAY_H
|
#ifndef _INTERNALS_DISPLAY_H
|
||||||
#define _INTERNALS_DISPLAY_H 1
|
#define _INTERNALS_DISPLAY_H 1
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
extern int *vram;
|
extern int *vram;
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Rectangle masks.
|
||||||
|
//
|
||||||
|
// The concept of 'rectangle masks' is used several times in this module.
|
||||||
|
// It is based on the fact that an operation that affects a rectangle acts
|
||||||
|
// the same on all its lines. Therefore the behavior of the operation is
|
||||||
|
// determined by its behavior on a single line, which is represented using
|
||||||
|
// 'masks' whose bits indicate whether a pixel is affected (1) or not (0).
|
||||||
|
//
|
||||||
|
// For example when clearing the screen rectangle (16, 16, 112, 48), the
|
||||||
|
// masks will represent information '16 to 112 on x-axis', and will hold
|
||||||
|
// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These
|
||||||
|
// masks can then be used by setting vram[offset] &= ~masks[i]. This
|
||||||
|
// appears to be very flexible : for instance, vram[offset] ^= masks[i]
|
||||||
|
// will reverse the pixels in the same rectangle.
|
||||||
|
//
|
||||||
|
// This technique can also be used in more subtle cases with more complex
|
||||||
|
// patterns, but within this module it is unlikely to happen.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
adjustRectangle()
|
||||||
|
Adjusts the given rectangle coordinates to ensure that :
|
||||||
|
- the rectangle is entirely contained in the screen
|
||||||
|
- x1 < x2
|
||||||
|
- y1 < y2
|
||||||
|
which is needed when working with screen rectangles.
|
||||||
|
*/
|
||||||
|
void adjustRectangle(int *x1, int *y1, int *x2, int *y2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
getMasks()
|
||||||
|
Computes the rectangle masks needed to affect pixels located between x1
|
||||||
|
and x2 (both included). The four masks are stored in the third argument
|
||||||
|
(seen as an array).
|
||||||
|
*/
|
||||||
|
void getMasks(int x1, int x2, uint32_t *masks);
|
||||||
|
|
||||||
#endif // _INTERNALS_DISPLAY_H
|
#endif // _INTERNALS_DISPLAY_H
|
||||||
|
|
32
include/internals/stdio.h
Normal file
32
include/internals/stdio.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// standard library module: stdio
|
||||||
|
//
|
||||||
|
// Handles most input/output for the program. This module does not
|
||||||
|
// interact with the file system directly.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef _INTERNALS_STDIO_H
|
||||||
|
#define _INTERNALS_STDIO_H 1
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Formatted printing.
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef __stdio_buffer_size
|
||||||
|
#define __stdio_buffer_size 256
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern char __stdio_buffer[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
__printf()
|
||||||
|
Formatted printing to the stdio buffer.
|
||||||
|
*/
|
||||||
|
int __printf(size_t size, const char *format, va_list args);
|
||||||
|
|
||||||
|
#endif // _INTERNALS_STDIO_H
|
|
@ -1,3 +1,12 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// gint standard module: setjmp
|
||||||
|
//
|
||||||
|
// Long jumps. The register contents are saved in a buffer when setjmp()
|
||||||
|
// is called and restored at any time when longjmp() performs the jump.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
#ifndef _SETJMP_H
|
#ifndef _SETJMP_H
|
||||||
#define _SETJMP_H 1
|
#define _SETJMP_H 1
|
||||||
|
|
||||||
|
@ -12,13 +21,13 @@ typedef unsigned int jmp_buf[16];
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
setjmp()
|
setjmp() O(1)
|
||||||
Configures a jump by saving data to the given jump buffer.
|
Configures a jump by saving data to the given jump buffer.
|
||||||
*/
|
*/
|
||||||
int setjmp(jmp_buf env);
|
int setjmp(jmp_buf env);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
longjmp()
|
longjmp() O(1)
|
||||||
Performs a long jump.
|
Performs a long jump.
|
||||||
*/
|
*/
|
||||||
void longjmp(jmp_buf env, int value);
|
void longjmp(jmp_buf env, int value);
|
||||||
|
|
44
include/stdio.h
Normal file
44
include/stdio.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// standard library module: stdio
|
||||||
|
//
|
||||||
|
// Handles most input/output for the program. This module does not
|
||||||
|
// interact with the file system directly.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef _STDIO_H
|
||||||
|
#define _STDIO_H 1
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Formatted printing.
|
||||||
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
sprintf()
|
||||||
|
Prints to a string.
|
||||||
|
*/
|
||||||
|
int sprintf(char *str, const char *format, ...);
|
||||||
|
|
||||||
|
/*
|
||||||
|
snprintf()
|
||||||
|
Prints to a string with a size limit.
|
||||||
|
*/
|
||||||
|
int snprintf(char *str, size_t size, const char *format, ...);
|
||||||
|
|
||||||
|
/*
|
||||||
|
vsprintf()
|
||||||
|
Prints to a string from an argument list.
|
||||||
|
*/
|
||||||
|
int vsprintf(char *str, const char *format, va_list args);
|
||||||
|
|
||||||
|
/*
|
||||||
|
vsnprintf()
|
||||||
|
The most generic formatted printing function around there.
|
||||||
|
*/
|
||||||
|
int vsnprintf(char *str, size_t size, const char *format, va_list args);
|
||||||
|
|
||||||
|
#endif // _STDIO_H
|
|
@ -1,3 +1,12 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// standard library module: stdlib
|
||||||
|
//
|
||||||
|
// Provides standard functionalities such as dynamic allocation,
|
||||||
|
// string/numeric conversion, and abort calls.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
#ifndef _STDLIB_H
|
#ifndef _STDLIB_H
|
||||||
#define _STDLIB_H 1
|
#define _STDLIB_H 1
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// standard library module: string
|
||||||
|
//
|
||||||
|
// String manipulation using NUL-terminated byte arrays, without extended
|
||||||
|
// characters.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
#ifndef _STRING_H
|
#ifndef _STRING_H
|
||||||
#define _STRING_H 1
|
#define _STRING_H 1
|
||||||
|
|
||||||
|
@ -28,9 +37,27 @@ void *memset(void *destination, int byte, size_t byte_number);
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
strlen() O(length)
|
strlen() O(len(str))
|
||||||
Returns the length of a string.
|
Returns the length of a string.
|
||||||
*/
|
*/
|
||||||
size_t strlen(const char *str);
|
size_t strlen(const char *str);
|
||||||
|
|
||||||
|
/*
|
||||||
|
strcpy() O(len(source))
|
||||||
|
Copies a string to another.
|
||||||
|
*/
|
||||||
|
char *strcpy(char *destination, const char *source);
|
||||||
|
|
||||||
|
/*
|
||||||
|
strchr() O(len(str))
|
||||||
|
Searches a character in a string.
|
||||||
|
*/
|
||||||
|
const char *strchr(const char *str, int value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
strncpy() O(min(len(source), size))
|
||||||
|
Copies part of a string to another.
|
||||||
|
*/
|
||||||
|
char *strncpy(char *destination, const char *source, size_t size);
|
||||||
|
|
||||||
#endif // _STRING_H
|
#endif // _STRING_H
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
//
|
//
|
||||||
// gint drawing module: tales
|
// gint drawing module: tales
|
||||||
//
|
//
|
||||||
// Text displaying. Does some good optimization, though requires dynamic
|
// Text displaying. Does some pretty good optimization, though requires
|
||||||
// allocation.
|
// dynamic allocation. The stack is used.
|
||||||
//
|
//
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
@ -113,4 +113,16 @@ void dtext(const char *str, int x, int y);
|
||||||
*/
|
*/
|
||||||
void gtext(const char *str, int x, int y);
|
void gtext(const char *str, int x, int y);
|
||||||
|
|
||||||
|
/*
|
||||||
|
dprint()
|
||||||
|
Prints a formatted string. Works the same as printf().
|
||||||
|
*/
|
||||||
|
void dprint(int x, int y, const char *format, ...);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gprint()
|
||||||
|
Prints a formatted string. Works the same as printf().
|
||||||
|
*/
|
||||||
|
void gprint(int x, int y, const char *format, ...);
|
||||||
|
|
||||||
#endif // _TALES_H
|
#endif // _TALES_H
|
||||||
|
|
BIN
libc.a
BIN
libc.a
Binary file not shown.
BIN
libgint.a
BIN
libgint.a
Binary file not shown.
|
@ -1,7 +1,7 @@
|
||||||
#include <internals/bopti.h>
|
#include <internals/bopti.h>
|
||||||
|
|
||||||
// Monochrome video ram, light and dark buffers (in this order).
|
// Monochrome video ram, light and dark buffers (in this order).
|
||||||
int *vram, *v1, *v2;
|
int *bopti_vram, *bopti_v1, *bopti_v2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bopti_op()
|
bopti_op()
|
||||||
|
@ -19,11 +19,11 @@ void bopti_op_mono(int offset, uint32_t operator, struct Command *c)
|
||||||
switch(c->channel)
|
switch(c->channel)
|
||||||
{
|
{
|
||||||
case Channel_Mono:
|
case Channel_Mono:
|
||||||
vram[offset] |= operator;
|
bopti_vram[offset] |= operator;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Channel_FullAlpha:
|
case Channel_FullAlpha:
|
||||||
vram[offset] &= ~operator;
|
bopti_vram[offset] &= ~operator;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -37,21 +37,21 @@ void bopti_op_gray(int offset, uint32_t operator, struct Command *c)
|
||||||
switch(c->channel)
|
switch(c->channel)
|
||||||
{
|
{
|
||||||
case Channel_Mono:
|
case Channel_Mono:
|
||||||
v1[offset] |= operator;
|
bopti_v1[offset] |= operator;
|
||||||
v2[offset] |= operator;
|
bopti_v2[offset] |= operator;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Channel_Light:
|
case Channel_Light:
|
||||||
v1[offset] |= operator;
|
bopti_v1[offset] |= operator;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Channel_Dark:
|
case Channel_Dark:
|
||||||
v2[offset] |= operator;
|
bopti_v2[offset] |= operator;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Channel_FullAlpha:
|
case Channel_FullAlpha:
|
||||||
v1[offset] &= ~operator;
|
bopti_v1[offset] &= ~operator;
|
||||||
v2[offset] &= ~operator;
|
bopti_v2[offset] &= ~operator;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Channel_LightAlpha:
|
case Channel_LightAlpha:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include <internals/bopti.h>
|
#include <internals/bopti.h>
|
||||||
#include <display.h>
|
#include <internals/display.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dimage()
|
dimage()
|
||||||
|
@ -34,7 +34,7 @@ void dimage(struct Image *img, int x, int y)
|
||||||
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
|
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
|
||||||
else getMasks(0, actual_width + x - 1, command.masks);
|
else getMasks(0, actual_width + x - 1, command.masks);
|
||||||
|
|
||||||
vram = display_getCurrentVRAM();
|
bopti_vram = display_getCurrentVRAM();
|
||||||
|
|
||||||
while(format)
|
while(format)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include <internals/bopti.h>
|
#include <internals/bopti.h>
|
||||||
#include <display.h>
|
#include <internals/display.h>
|
||||||
#include <gray.h>
|
#include <gray.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -34,8 +34,8 @@ void gimage(struct Image *img, int x, int y)
|
||||||
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
|
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
|
||||||
else getMasks(0, actual_width + x - 1, command.masks);
|
else getMasks(0, actual_width + x - 1, command.masks);
|
||||||
|
|
||||||
v1 = gray_lightVRAM();
|
bopti_v1 = gray_lightVRAM();
|
||||||
v2 = gray_darkVRAM();
|
bopti_v2 = gray_darkVRAM();
|
||||||
|
|
||||||
while(format)
|
while(format)
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
@ -9,6 +9,7 @@
|
||||||
#include <gray.h>
|
#include <gray.h>
|
||||||
#include <screen.h>
|
#include <screen.h>
|
||||||
#include <timer.h>
|
#include <timer.h>
|
||||||
|
#include <mpu.h>
|
||||||
|
|
||||||
static int internal_vrams[3][256];
|
static int internal_vrams[3][256];
|
||||||
static const void *vrams[4];
|
static const void *vrams[4];
|
||||||
|
@ -151,6 +152,6 @@ void gray_init(void)
|
||||||
vrams[2] = (const void *)internal_vrams[1];
|
vrams[2] = (const void *)internal_vrams[1];
|
||||||
vrams[3] = (const void *)internal_vrams[2];
|
vrams[3] = (const void *)internal_vrams[2];
|
||||||
|
|
||||||
delays[0] = 993;
|
delays[0] = isSH3() ? 985 : 994;
|
||||||
delays[1] = 1609;
|
delays[1] = 1609;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ static void (*rtc_callback)(void) = NULL;
|
||||||
Sets the callback function for the real-time clock interrupt. If
|
Sets the callback function for the real-time clock interrupt. If
|
||||||
frequency is non-NULL, the clock frequency is set to the given value.
|
frequency is non-NULL, the clock frequency is set to the given value.
|
||||||
*/
|
*/
|
||||||
void gint_setRTCCallback(void (*callback)(void), enum RTCFrequency frequency)
|
void rtc_setCallback(void (*callback)(void), enum RTCFrequency frequency)
|
||||||
{
|
{
|
||||||
rtc_callback = callback;
|
rtc_callback = callback;
|
||||||
if(frequency < 1 || frequency > 7) return;
|
if(frequency < 1 || frequency > 7) return;
|
||||||
|
@ -30,7 +30,7 @@ void gint_setRTCCallback(void (*callback)(void), enum RTCFrequency frequency)
|
||||||
Returns the callback function. If frequency is non-NULL, it is set to
|
Returns the callback function. If frequency is non-NULL, it is set to
|
||||||
the current frequency value.
|
the current frequency value.
|
||||||
*/
|
*/
|
||||||
void (*gint_getRTCCallback(enum RTCFrequency *frequency))(void)
|
void (*rtc_getCallback(enum RTCFrequency *frequency))(void)
|
||||||
{
|
{
|
||||||
if(!frequency) return rtc_callback;
|
if(!frequency) return rtc_callback;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
gint standard module: setjmp
|
standard library module: setjmp
|
||||||
|
|
||||||
Long jumps. The register contents are saved in a buffer when setjmp()
|
Long jumps. The register contents are saved in a buffer when setjmp()
|
||||||
is called and restored at any time when longjmp() performs the jump.
|
is called and restored at any time when longjmp() performs the jump.
|
||||||
|
|
19
src/stdio/snprintf.c
Normal file
19
src/stdio/snprintf.c
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include <internals/stdio.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
snprintf()
|
||||||
|
Prints to a string with a size limit.
|
||||||
|
*/
|
||||||
|
int snprintf(char *str, size_t size, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
|
||||||
|
int x = __printf(size, format, args);
|
||||||
|
strncpy(str, __stdio_buffer, size);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
return x;
|
||||||
|
}
|
19
src/stdio/sprintf.c
Normal file
19
src/stdio/sprintf.c
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include <internals/stdio.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
sprintf()
|
||||||
|
Prints to a string.
|
||||||
|
*/
|
||||||
|
int sprintf(char *str, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
|
||||||
|
int x = __printf(0, format, args);
|
||||||
|
strncpy(str, __stdio_buffer, __stdio_buffer_size);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
return x;
|
||||||
|
}
|
912
src/stdio/stdio_format.c
Normal file
912
src/stdio/stdio_format.c
Normal file
|
@ -0,0 +1,912 @@
|
||||||
|
#include <internals/stdio.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Internal buffer.
|
||||||
|
|
||||||
|
Using a buffer *really* simplifies everything. But it also has
|
||||||
|
disadvantages, such a memory loss and limited output size.
|
||||||
|
|
||||||
|
So, in case we find a possibility to get rid of this buffer, we will
|
||||||
|
just have to change function character(), which is for now the only
|
||||||
|
function that directly accesses the buffer.
|
||||||
|
*/
|
||||||
|
char __stdio_buffer[__stdio_buffer_size];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Format composed types.
|
||||||
|
|
||||||
|
Format structure handles everything in a format, from data type to
|
||||||
|
given value, including alternative forms, alignment and digit numbers.
|
||||||
|
|
||||||
|
A format is made of a data type, which can be altered by a size option,
|
||||||
|
a number of integer and decimal digits, and additional flags.
|
||||||
|
|
||||||
|
The FormatFlags enumeration handles the various flags that can be added
|
||||||
|
to a printf()-family format.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum FormatFlags
|
||||||
|
{
|
||||||
|
// Option '#' specifies alternatives forms, mainly '0' and '0x'
|
||||||
|
// prefixes in integer display.
|
||||||
|
Alternative = 1,
|
||||||
|
// Under specific conditions, zero-padding may be used instead of
|
||||||
|
// whitespace-padding.
|
||||||
|
ZeroPadded = 2,
|
||||||
|
// Left alignment specifies that additional spaces should be added
|
||||||
|
// after the value.
|
||||||
|
LeftAlign = 4,
|
||||||
|
// In numeric display, this forces a blank sign to be written before
|
||||||
|
// positive values.
|
||||||
|
BlankSign = 8,
|
||||||
|
// In numeric display, this forces an explicit sign in all cases. This
|
||||||
|
// option overrides BlankSign (see __printf() description for further
|
||||||
|
// information on option precedence and influence).
|
||||||
|
ForceSign = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Format
|
||||||
|
{
|
||||||
|
// Format type, one of 'diouxXcs' ('eEfFgGaApnm' still to add).
|
||||||
|
char type;
|
||||||
|
// Format size, one of 'l', 'h', 'i' ('i' means 'hh').
|
||||||
|
char size;
|
||||||
|
|
||||||
|
// Number of characters printed.
|
||||||
|
int characters;
|
||||||
|
// Number of digits after the dot.
|
||||||
|
int precision;
|
||||||
|
|
||||||
|
// Various flags.
|
||||||
|
enum FormatFlags flags;
|
||||||
|
|
||||||
|
// Value to output.
|
||||||
|
union
|
||||||
|
{
|
||||||
|
// Signed int with formats %c, %d and %i.
|
||||||
|
signed int _int;
|
||||||
|
// Insigned int with formats %o, %u, %x and %X.
|
||||||
|
unsigned int _unsigned;
|
||||||
|
// Double with formats %f, %F, %e, %E, %g and %G.
|
||||||
|
// double _double;
|
||||||
|
// String pointer with format %s.
|
||||||
|
const char *_pointer;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Static declarations.
|
||||||
|
//---
|
||||||
|
|
||||||
|
// Outputs a character in the buffer. Updates counters.
|
||||||
|
static void character(int c);
|
||||||
|
// Outputs n timers the given character.
|
||||||
|
static void character_n(int c, int n);
|
||||||
|
// Reads a format from the given string pointer address (must begin with '%').
|
||||||
|
static struct Format get_format(const char **pointer);
|
||||||
|
// Computes the number of spaces and zeros to add to the bare output.
|
||||||
|
static void get_spacing(struct Format format, int *begin_spaces, int *sign,
|
||||||
|
int *zeros, int length, int *end_spaces);
|
||||||
|
|
||||||
|
static void format_di (struct Format format);
|
||||||
|
static void format_u (struct Format format);
|
||||||
|
static void format_oxX (struct Format format);
|
||||||
|
// static void format_e (struct Format format);
|
||||||
|
static void format_c (struct Format format);
|
||||||
|
static void format_s (struct Format format);
|
||||||
|
static void format_p (struct Format format);
|
||||||
|
|
||||||
|
#define abs(x) ((x) < 0 ? -(x) : (x))
|
||||||
|
|
||||||
|
// Number of characters currently written.
|
||||||
|
static size_t written = 0;
|
||||||
|
// Total number of function calls (characters theoretically written).
|
||||||
|
static size_t total = 0;
|
||||||
|
// Maximum number of characters to output.
|
||||||
|
static size_t max = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
character()
|
||||||
|
Outputs a character to the buffer. This function centralizes all the
|
||||||
|
buffer interface, so that if we come to remove it for property reasons,
|
||||||
|
we would just have to edit this function.
|
||||||
|
|
||||||
|
Static variables written and total are both needed, because the
|
||||||
|
terminating NUL character may be written after the maximum has been
|
||||||
|
reached.
|
||||||
|
In other words, when the function ends, we need to have a variable
|
||||||
|
counting the current position in the buffer (written), and one other
|
||||||
|
containing the total number of theoretic characters (total) because
|
||||||
|
these two values may be different.
|
||||||
|
|
||||||
|
Of course the three variables need to be initialized before using this
|
||||||
|
function.
|
||||||
|
*/
|
||||||
|
static void character(int c)
|
||||||
|
{
|
||||||
|
// If there is space left in the buffer.
|
||||||
|
if(written < max - 1) __stdio_buffer[written++] = c;
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
character_n()
|
||||||
|
Outputs n times the same character. Thought to be used to output spaces
|
||||||
|
or zeros without heavy loops.
|
||||||
|
*/
|
||||||
|
static void character_n(int c, int n)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while(i++ < n) character(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
get_format()
|
||||||
|
Reads the format from the given string pointer and returns a
|
||||||
|
corresponding Format structure. The string pointer points to is also
|
||||||
|
modified, so that is points to the first character after the format.
|
||||||
|
This function expects **pointer == '%'.
|
||||||
|
*/
|
||||||
|
static struct Format get_format(const char **pointer)
|
||||||
|
{
|
||||||
|
const char *convspec = "diouxXeEfFgGaAcspnm";
|
||||||
|
struct Format format;
|
||||||
|
|
||||||
|
const char *string = *pointer, *ptr;
|
||||||
|
int c, i;
|
||||||
|
char precision[10];
|
||||||
|
|
||||||
|
// Moving the string pointer after the '%' character.
|
||||||
|
string++;
|
||||||
|
|
||||||
|
// Initializing structure.
|
||||||
|
format.type = 0;
|
||||||
|
format.size = 0;
|
||||||
|
format.flags = 0;
|
||||||
|
// Initializing digit counts.
|
||||||
|
format.characters = -1;
|
||||||
|
format.precision = -1;
|
||||||
|
|
||||||
|
// Parsing the format string. Testing each character until a
|
||||||
|
// conversion specifier is found.
|
||||||
|
while((c = *string))
|
||||||
|
{
|
||||||
|
// Looking for a conversion specifier.
|
||||||
|
ptr = strchr(convspec, c);
|
||||||
|
if(ptr)
|
||||||
|
{
|
||||||
|
format.type = *ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looking for a left precision string (number of digits before
|
||||||
|
// the dot), introduced by a non-null digit.
|
||||||
|
if(c >= '1' && c <= '9')
|
||||||
|
{
|
||||||
|
format.characters = 0;
|
||||||
|
for(i = 0; i < 9 && isdigit(*string); string++)
|
||||||
|
{
|
||||||
|
format.characters *= 10;
|
||||||
|
format.characters += *string - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// As pointer is now pointing to the next character,
|
||||||
|
// we want to try tests again from the beginning.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looking for a right precision string (number of digits after
|
||||||
|
// the dot), introduced by a point.
|
||||||
|
if(c == '.')
|
||||||
|
{
|
||||||
|
string++;
|
||||||
|
if(!isdigit(*string)) continue;
|
||||||
|
|
||||||
|
format.precision = 0;
|
||||||
|
for(i = 0; i < 9 && isdigit(*string); string++)
|
||||||
|
{
|
||||||
|
format.precision *= 10;
|
||||||
|
format.precision += *string - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// As pointer is now pointing on the next character,
|
||||||
|
// we want to try tests again from the beginning.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handling predefined characters.
|
||||||
|
switch(*string)
|
||||||
|
{
|
||||||
|
// Length modifiers.
|
||||||
|
case 'h':
|
||||||
|
format.size = 'h' + (format.size == 'h');
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
case 'L':
|
||||||
|
case 'z':
|
||||||
|
case 't':
|
||||||
|
format.size = *string;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Flags.
|
||||||
|
case '#':
|
||||||
|
format.flags |= Alternative;
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
format.flags |= ZeroPadded;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
format.flags |= LeftAlign;
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
format.flags |= BlankSign;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
format.flags |= ForceSign;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the format hasn't ended, the type attribute is left to zero and
|
||||||
|
// the main loop will handle failure and break. Nothing has to be done
|
||||||
|
// here.
|
||||||
|
|
||||||
|
*pointer = string + 1;
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
get_spacing()
|
||||||
|
Computes the arrangement of beginning spaces, sign, zeros, pure value
|
||||||
|
and ending spaces in formats.
|
||||||
|
This formatting follows a recurrent model which is centralized in this
|
||||||
|
function. Note that you can't have `begin_spaces` and `end_spaces`
|
||||||
|
both non-zero: at least one is null.
|
||||||
|
*/
|
||||||
|
static void get_spacing(struct Format format, int *begin_spaces, int *sign,
|
||||||
|
int *zeros, int length, int *end_spaces)
|
||||||
|
{
|
||||||
|
// Using a list of types involving a sign.
|
||||||
|
const char *signed_types = "dieEfFgGaA";
|
||||||
|
int spaces;
|
||||||
|
// Digits represents pure output + zeros (don't mix up with the *real*
|
||||||
|
// displayed digits).
|
||||||
|
int digits;
|
||||||
|
int left = format.flags & LeftAlign;
|
||||||
|
|
||||||
|
// Getting the total number of digits.
|
||||||
|
switch(format.type)
|
||||||
|
{
|
||||||
|
// In integer display, the number of digits output is specified in the
|
||||||
|
// precision.
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
case 'u':
|
||||||
|
digits = format.precision;
|
||||||
|
if(digits < length) digits = length;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Binary display has prefixes such as '0' and '0x'.
|
||||||
|
case 'o':
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
digits = format.precision;
|
||||||
|
if(digits == -1) digits = length;
|
||||||
|
|
||||||
|
if(format.flags & Alternative)
|
||||||
|
{
|
||||||
|
int hexa = (format.type == 'x' || format.type == 'X');
|
||||||
|
digits += 1 + hexa;
|
||||||
|
length += 1 + hexa;
|
||||||
|
}
|
||||||
|
if(digits < length) digits = length;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Other formats do not have additional zeros.
|
||||||
|
default:
|
||||||
|
digits = length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sign)
|
||||||
|
{
|
||||||
|
if(strchr(signed_types, format.type))
|
||||||
|
{
|
||||||
|
if(format.flags & BlankSign) *sign = ' ';
|
||||||
|
// Option '+' overrides option ' '.
|
||||||
|
if(format.flags & ForceSign) *sign = '+';
|
||||||
|
// And of course negative sign overrides everything!
|
||||||
|
if(format.type == 'd' || format.type == 'i')
|
||||||
|
{
|
||||||
|
if(format._int < 0) *sign = '-';
|
||||||
|
}
|
||||||
|
// else if(format._double < 0) *sign = '-';
|
||||||
|
|
||||||
|
}
|
||||||
|
else *sign = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computing the number of spaces.
|
||||||
|
spaces = format.characters - digits;
|
||||||
|
// Computing the number of zeros.
|
||||||
|
*zeros = digits - length;
|
||||||
|
|
||||||
|
// Removing a space when a sign appears.
|
||||||
|
if(sign && *sign) spaces--;
|
||||||
|
|
||||||
|
// Option '0' translates spaces to zeros, but only if no precision is
|
||||||
|
// specified; additionally, left alignment overrides zero-padding.
|
||||||
|
if(!left && format.precision == -1 && format.flags & ZeroPadded)
|
||||||
|
{
|
||||||
|
*zeros += spaces;
|
||||||
|
spaces = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting the correct spaces number to the computed value, depending
|
||||||
|
// on the left alignment parameter.
|
||||||
|
*begin_spaces = left ? 0 : spaces;
|
||||||
|
*end_spaces = left ? spaces : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
__printf()
|
||||||
|
|
||||||
|
Basic buffered formatted printing function. Fully-featured, so that
|
||||||
|
ant call to a printf()-family function can be translated into a
|
||||||
|
__printf() call.
|
||||||
|
|
||||||
|
It always returns the number of characters of the theoretic formatted
|
||||||
|
output. The real output may be limited in size by the given size
|
||||||
|
argument when working with nprintf()-family functions, or the internal
|
||||||
|
buffer itself.
|
||||||
|
|
||||||
|
The Flags structure isn't necessary, but it simplifies a lot format
|
||||||
|
argument handling (because flag effects depend on format type, which
|
||||||
|
is unknown when the flags are read). Also, length modifiers 'hh' is
|
||||||
|
stored as 'i' to simplify structure handling. 'll' is not supported.
|
||||||
|
Format '%LF' is allowed by C99 and therefore supported.
|
||||||
|
|
||||||
|
Generic information on options precedence and influence.
|
||||||
|
- Influences of integer part and mantissa digit numbers depend on
|
||||||
|
the type of data that is being displayed.
|
||||||
|
- Option '#' doesn't contend with any other.
|
||||||
|
- Option '+' overrides options ' '.
|
||||||
|
- In integer display, option '0' translates spaces to zeros, but
|
||||||
|
only if no decimal digit number is specified.
|
||||||
|
The option '-' also overrides it, forcing whitespaces to be
|
||||||
|
written at the end of the format.
|
||||||
|
|
||||||
|
Limit of function.
|
||||||
|
- Internal buffer size (should be customizable with a -D option
|
||||||
|
when compiling).
|
||||||
|
- Precision values (format %a.b) are written on 8 bits, therefore
|
||||||
|
limited to 127.
|
||||||
|
|
||||||
|
Unsupported features.
|
||||||
|
- Flag character ''' (single quote) for thousands grouping
|
||||||
|
- Flag character 'I', that outputs locale's digits (glibc 2.2)
|
||||||
|
- Length modifiers 'll' and 'q' (libc 5 and 4.4 BSD)
|
||||||
|
- This is not really a feature but incorrect characters in
|
||||||
|
formats are ignored and don't invalidate the format.
|
||||||
|
*/
|
||||||
|
int __printf(size_t size, const char *string, va_list args)
|
||||||
|
{
|
||||||
|
struct Format format;
|
||||||
|
|
||||||
|
// Avoiding overflow by adjusting the size argument.
|
||||||
|
if(!size || size > __stdio_buffer_size)
|
||||||
|
size = __stdio_buffer_size;
|
||||||
|
|
||||||
|
// Initializing character() working values.
|
||||||
|
written = 0;
|
||||||
|
total = 0;
|
||||||
|
max = size;
|
||||||
|
|
||||||
|
// Parsing the format string. At each iteration, a literal character, a
|
||||||
|
// '%%' identifier or a format is parsed.
|
||||||
|
while(*string)
|
||||||
|
{
|
||||||
|
// Literal text.
|
||||||
|
if(*string != '%')
|
||||||
|
{
|
||||||
|
character(*string++);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Literal '%'.
|
||||||
|
if(string[1] == '%')
|
||||||
|
{
|
||||||
|
string += 2;
|
||||||
|
character('%');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getting the format.
|
||||||
|
format = get_format(&string);
|
||||||
|
if(!format.type) break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Displaying an information message.
|
||||||
|
printf(
|
||||||
|
"Format found :%s%c%c, options %d, and %d.%d "
|
||||||
|
"digits\n",
|
||||||
|
format.size ? " " : "",
|
||||||
|
format.size ? format.size : ' ',
|
||||||
|
format.type,
|
||||||
|
format.flags,
|
||||||
|
format.digits,
|
||||||
|
format.mantissa
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch(format.type)
|
||||||
|
{
|
||||||
|
// Signed integers.
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
format._int = va_arg(args, signed int);
|
||||||
|
|
||||||
|
// Reducing value depending on format size.
|
||||||
|
switch(format.size)
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
format._int &= 0x0000ffff;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
format._int &= 0x000000ff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
format_di(format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Unsigned integers.
|
||||||
|
case 'u':
|
||||||
|
format._unsigned = va_arg(args, unsigned int);
|
||||||
|
format_u(format);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
format._unsigned = va_arg(args, unsigned int);
|
||||||
|
format_oxX(format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* // Exponent notation.
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
format._double = va_arg(args, double);
|
||||||
|
format_e(format);
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
// Characters.
|
||||||
|
case 'c':
|
||||||
|
format._int = va_arg(args, signed int) & 0xff;
|
||||||
|
format_c(format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Strings.
|
||||||
|
case 's':
|
||||||
|
format._pointer = va_arg(args, const char *);
|
||||||
|
format_s(format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Pointers.
|
||||||
|
case 'p':
|
||||||
|
format._unsigned = va_arg(args, unsigned int);
|
||||||
|
format_p(format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Character counter.
|
||||||
|
case 'n':
|
||||||
|
*va_arg(args, int *) = written;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding a terminating NUL character. Function character() should have
|
||||||
|
// left an empty byte for that.
|
||||||
|
__stdio_buffer[written] = 0;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
format_di()
|
||||||
|
|
||||||
|
Subroutine itoa(). Writes the given signed integer to the internal
|
||||||
|
buffer, trough function character().
|
||||||
|
It is used by conversion specifiers 'd' and 'i'.
|
||||||
|
Options '#' and '0' have no effect.
|
||||||
|
*/
|
||||||
|
static void format_di(struct Format format)
|
||||||
|
{
|
||||||
|
// In integer display, character number includes pure digits and
|
||||||
|
// additional zeros and spacing.
|
||||||
|
// The precision represents the number of digits (pure digits and
|
||||||
|
// zeros) to print.
|
||||||
|
// For example: ' 0004', pure digits: 1, digits: 4, characters: 5.
|
||||||
|
|
||||||
|
int sign = 0;
|
||||||
|
signed int x = format._int;
|
||||||
|
// Using integers to store the number pure digits and additional spaces
|
||||||
|
// and zeros.
|
||||||
|
int bspaces, zeros, digits = 0, espaces;
|
||||||
|
// Using a multiplier to output digit in the correct order.
|
||||||
|
int multiplier = 1;
|
||||||
|
|
||||||
|
// Returning if the argument is null with an explicit precision of
|
||||||
|
// zero, but only if there are no spaces.
|
||||||
|
if(!x && format.characters == -1 && !format.precision) return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Computations.
|
||||||
|
//---
|
||||||
|
|
||||||
|
// Computing the number of digits and the multiplier.
|
||||||
|
x = abs(format._int);
|
||||||
|
if(!x) digits = 1;
|
||||||
|
else while(x)
|
||||||
|
{
|
||||||
|
digits++;
|
||||||
|
x /= 10;
|
||||||
|
if(x) multiplier *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getting the corresponding spacing.
|
||||||
|
get_spacing(format, &bspaces, &sign, &zeros, digits, &espaces);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Output.
|
||||||
|
//---
|
||||||
|
|
||||||
|
character_n(' ', bspaces);
|
||||||
|
if(sign) character(sign);
|
||||||
|
character_n('0', zeros);
|
||||||
|
|
||||||
|
x = abs(format._int);
|
||||||
|
// Writing the pure digits, except if the value is null with an
|
||||||
|
// explicit precision of zero.
|
||||||
|
if(x || format.precision) while(multiplier)
|
||||||
|
{
|
||||||
|
character((x / multiplier) % 10 + '0');
|
||||||
|
multiplier /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
character_n(' ', espaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
format_u()
|
||||||
|
Unsigned integers in base 10. Options ' ', '+' and '#' have no effect.
|
||||||
|
*/
|
||||||
|
static void format_u(struct Format format)
|
||||||
|
{
|
||||||
|
int bspaces, zeros, digits = 0, espaces;
|
||||||
|
int x = format._unsigned;
|
||||||
|
int multiplier = 1;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
// Computing number of digits.
|
||||||
|
if(!x) digits = 1;
|
||||||
|
else while(x)
|
||||||
|
{
|
||||||
|
digits++;
|
||||||
|
x /= 10;
|
||||||
|
if(x) multiplier *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_spacing(format, &bspaces, NULL, &zeros, digits, &espaces);
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Output.
|
||||||
|
//---
|
||||||
|
|
||||||
|
character_n(' ', bspaces);
|
||||||
|
character_n('0', zeros);
|
||||||
|
|
||||||
|
x = format._unsigned;
|
||||||
|
while(multiplier)
|
||||||
|
{
|
||||||
|
character('0' + (x / multiplier) % 10);
|
||||||
|
multiplier /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
character_n(' ', espaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
format_oxX()
|
||||||
|
Unsigned integers in base 8 or 16.
|
||||||
|
Since the argument is unsigned, options ' ' and '+' have no effect.
|
||||||
|
Option '#' adds prefix '0' in octal or '0x' in hexadecimal.
|
||||||
|
*/
|
||||||
|
static void format_oxX(struct Format format)
|
||||||
|
{
|
||||||
|
// In unsigned display, the digit number specifies the minimal number
|
||||||
|
// of characters that should be output. If the prefix (alternative
|
||||||
|
// form) is present, it is part of this count.
|
||||||
|
// Integer part and decimal part digit numbers behave the same way as
|
||||||
|
// in signed integer display.
|
||||||
|
|
||||||
|
// Using integers to store the number of digits, zeros and spaces.
|
||||||
|
int bspaces, zeros, digits = 0, espaces;
|
||||||
|
unsigned int x = format._unsigned;
|
||||||
|
int multiplier = 0, shift, mask;
|
||||||
|
int c, disp;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Computations.
|
||||||
|
//---
|
||||||
|
|
||||||
|
shift = (format.type == 'o') ? (3) : (4);
|
||||||
|
mask = (1 << shift) - 1;
|
||||||
|
disp = (format.type == 'x') ? (39) : (7);
|
||||||
|
|
||||||
|
// Computing number of digits.
|
||||||
|
if(!x) digits = 1;
|
||||||
|
else while(x)
|
||||||
|
{
|
||||||
|
digits++;
|
||||||
|
x >>= shift;
|
||||||
|
if(x) multiplier += shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getting the spacing distribution.
|
||||||
|
get_spacing(format, &bspaces, NULL, &zeros, digits, &espaces);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Output.
|
||||||
|
//---
|
||||||
|
|
||||||
|
character_n(' ', bspaces);
|
||||||
|
x = format._unsigned;
|
||||||
|
|
||||||
|
// Writing the alternative form prefix.
|
||||||
|
if(format.flags & Alternative && x)
|
||||||
|
{
|
||||||
|
character('0');
|
||||||
|
if(format.type != 'o') character(format.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
character_n('0', zeros);
|
||||||
|
|
||||||
|
// Extracting the digits.
|
||||||
|
while(multiplier >= 0)
|
||||||
|
{
|
||||||
|
c = (x >> multiplier) & mask;
|
||||||
|
c += '0' + (c > 9) * disp;
|
||||||
|
|
||||||
|
character(c);
|
||||||
|
multiplier -= shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
character_n(' ', espaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
format_e()
|
||||||
|
Exponent notation. Option '#' has no effect.
|
||||||
|
|
||||||
|
static void format_e(struct Format format)
|
||||||
|
{
|
||||||
|
// In exponent display, the precision is the number of digits after the
|
||||||
|
// dot.
|
||||||
|
|
||||||
|
// Using an integer to store the number exponent.
|
||||||
|
int exponent = 0;
|
||||||
|
// Using a double value for temporary computations, and another to
|
||||||
|
// store the format parameter.
|
||||||
|
double tmp = 1, x = format._double;
|
||||||
|
// Using spacing variables. Default length is for '0.e+00';
|
||||||
|
int bspaces, zeros, sign, length = 6, espaces;
|
||||||
|
// Using an iterator and a multiplier.
|
||||||
|
int i, mul;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Computations.
|
||||||
|
//---
|
||||||
|
|
||||||
|
// Computing the exponent. For positive exponents, increasing until
|
||||||
|
// the temporary value gets greater than x.
|
||||||
|
if(x > 1)
|
||||||
|
{
|
||||||
|
// Looping until we haven't reached a greater exponent.
|
||||||
|
while(tmp < x)
|
||||||
|
{
|
||||||
|
// Incrementing the exponent.
|
||||||
|
exponent++;
|
||||||
|
// Multiplying the test value.
|
||||||
|
tmp *= 10;
|
||||||
|
}
|
||||||
|
// Removing an additional incrementation.
|
||||||
|
exponent--;
|
||||||
|
}
|
||||||
|
// For negative exponents, decreasing until it's lower.
|
||||||
|
else while(tmp > x)
|
||||||
|
{
|
||||||
|
// Decrementing the exponent.
|
||||||
|
exponent--;
|
||||||
|
// Dividing the test value.
|
||||||
|
tmp *= 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding a character if the exponent is greater that 100.
|
||||||
|
if(exponent >= 100) length++;
|
||||||
|
// Adding another one if it's greater than 1000.
|
||||||
|
if(exponent >= 1000) length++;
|
||||||
|
|
||||||
|
// Adjusting the format precision, defaulting to 6.
|
||||||
|
if(format.precision == -1) format.precision = 6;
|
||||||
|
// Adding the decimal digits.
|
||||||
|
length += format.precision;
|
||||||
|
|
||||||
|
// Getting the space repartition.
|
||||||
|
get_spacing(format, &bspaces, &sign, &zeros, length, &espaces);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Output.
|
||||||
|
//---
|
||||||
|
|
||||||
|
// Writing the beginning whitespaces.
|
||||||
|
character_n(' ', bspaces);
|
||||||
|
// Writing the sign if existing.
|
||||||
|
if(sign) character(sign);
|
||||||
|
// Writing the zeros.
|
||||||
|
character_n('0', zeros);
|
||||||
|
|
||||||
|
// Initializing x.
|
||||||
|
x = abs(format._double) / tmp;
|
||||||
|
// Writing the first digit.
|
||||||
|
character(x + '0');
|
||||||
|
character('.');
|
||||||
|
|
||||||
|
// Writing the decimal digits.
|
||||||
|
for(i = 0; i < format.precision; i++)
|
||||||
|
{
|
||||||
|
// Multiplying x by 10 and getting rid of the previous digit.
|
||||||
|
x = (x - (int)x) * 10;
|
||||||
|
// Writing the current digit.
|
||||||
|
character(x + '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing the exponent letter and its sign.
|
||||||
|
character(format.type);
|
||||||
|
character(exponent < 0 ? '-' : '+');
|
||||||
|
|
||||||
|
// Getting a positive exponent.
|
||||||
|
exponent = abs(exponent);
|
||||||
|
|
||||||
|
// Using a multiplier for the exponent.
|
||||||
|
if(exponent >= 1000) mul = 1000;
|
||||||
|
else if(exponent >= 100) mul = 100;
|
||||||
|
else mul = 10;
|
||||||
|
|
||||||
|
// Writing the exponent characters.
|
||||||
|
while(mul)
|
||||||
|
{
|
||||||
|
// Writing the next character.
|
||||||
|
character((exponent / mul) % 10 + '0');
|
||||||
|
// Dividing the multiplier.
|
||||||
|
mul *= 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing the ending whitespaces if left-aligned.
|
||||||
|
character_n(' ', espaces);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
format_c()
|
||||||
|
Character output. Only handles left alignment and spacing.
|
||||||
|
Options '#', '0', ' ' and '+', as well as mantissa digit number, have
|
||||||
|
no effect.
|
||||||
|
*/
|
||||||
|
static void format_c(struct Format format)
|
||||||
|
{
|
||||||
|
// In character display, the digit number represents the number of
|
||||||
|
// characters written, including the argument and additional
|
||||||
|
// whitespaces.
|
||||||
|
|
||||||
|
int spaces = format.characters - 1;
|
||||||
|
int left = format.flags & LeftAlign;
|
||||||
|
|
||||||
|
if(!left) character_n(' ', spaces);
|
||||||
|
character(format._int & 0xff);
|
||||||
|
if(left) character_n(' ', spaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
format_s()
|
||||||
|
String output. Spaces if needed.
|
||||||
|
*/
|
||||||
|
void format_s(struct Format format)
|
||||||
|
{
|
||||||
|
// In string display, the character number specify the minimum size of
|
||||||
|
// output (padded with whitespaces if needed) and the precision
|
||||||
|
// specify the maximum number of string characters output.
|
||||||
|
|
||||||
|
int string = format.precision;
|
||||||
|
int spaces;
|
||||||
|
|
||||||
|
const char *str = format._pointer;
|
||||||
|
int length, i;
|
||||||
|
int left = format.flags & LeftAlign;
|
||||||
|
|
||||||
|
// Computing length of string and number of whitespaces.
|
||||||
|
length = strlen(str);
|
||||||
|
if(string > length || string == -1) string = length;
|
||||||
|
spaces = format.characters - string;
|
||||||
|
|
||||||
|
if(!left) character_n(' ', spaces);
|
||||||
|
for(i = 0; i < string; i++) character(str[i]);
|
||||||
|
if(left) character_n(' ', spaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
format_p()
|
||||||
|
Pointer output. Simple hexadecimal dump. Prints "(nil)" if pointer is
|
||||||
|
NULL.
|
||||||
|
*/
|
||||||
|
void format_p(struct Format format)
|
||||||
|
{
|
||||||
|
// Pointer display falls back to %#08x in the pointer is non-null,
|
||||||
|
// "(nil)" otherwise.
|
||||||
|
|
||||||
|
unsigned int x = format._unsigned;
|
||||||
|
int bspaces, zeros, digits = 0, espaces;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
digits = x ? 10 : 5;
|
||||||
|
get_spacing(format, &bspaces, NULL, &zeros, digits, &espaces);
|
||||||
|
|
||||||
|
character_n(' ', bspaces);
|
||||||
|
character_n('0', zeros);
|
||||||
|
|
||||||
|
if(x)
|
||||||
|
{
|
||||||
|
character('0');
|
||||||
|
character('x');
|
||||||
|
while(x)
|
||||||
|
{
|
||||||
|
c = x >> 28;
|
||||||
|
c += '0' + 39 * (c > 9);
|
||||||
|
character(c);
|
||||||
|
x <<= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
character('(');
|
||||||
|
character('n');
|
||||||
|
character('i');
|
||||||
|
character('l');
|
||||||
|
character(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
character_n(' ', espaces);
|
||||||
|
}
|
15
src/stdio/vsnprintf.c
Normal file
15
src/stdio/vsnprintf.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <internals/stdio.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
vsnprintf()
|
||||||
|
The most generic formatted printing function around there.
|
||||||
|
*/
|
||||||
|
int vsnprintf(char *str, size_t size, const char *format, va_list args)
|
||||||
|
{
|
||||||
|
int x = __printf(size, format, args);
|
||||||
|
strncpy(str, __stdio_buffer, size);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
15
src/stdio/vsprintf.c
Normal file
15
src/stdio/vsprintf.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <internals/stdio.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
vsprintf()
|
||||||
|
Prints to a string from an argument list.
|
||||||
|
*/
|
||||||
|
int vsprintf(char *str, const char *format, va_list args)
|
||||||
|
{
|
||||||
|
int x = __printf(0, format, args);
|
||||||
|
strncpy(str, __stdio_buffer, __stdio_buffer_size);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
11
src/string/strchr.c
Normal file
11
src/string/strchr.c
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
strchr
|
||||||
|
Searches a character in a string.
|
||||||
|
*/
|
||||||
|
const char *strchr(const char *str, int value)
|
||||||
|
{
|
||||||
|
while(*str && *str != value) *str++;
|
||||||
|
return *str ? str : NULL;
|
||||||
|
}
|
11
src/string/strcpy.c
Normal file
11
src/string/strcpy.c
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
strcpy()
|
||||||
|
Copies a string to another.
|
||||||
|
*/
|
||||||
|
char *strcpy(char *destination, const char *source)
|
||||||
|
{
|
||||||
|
size_t length = strlen(source);
|
||||||
|
return memcpy(destination, source, length);
|
||||||
|
}
|
20
src/string/strncpy.c
Normal file
20
src/string/strncpy.c
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
strncpy()
|
||||||
|
Copies part of a string to another.
|
||||||
|
*/
|
||||||
|
char *strncpy(char *destination, const char *source, size_t size)
|
||||||
|
{
|
||||||
|
size_t length = strlen(source);
|
||||||
|
|
||||||
|
if(length >= size)
|
||||||
|
{
|
||||||
|
return memcpy(destination, source, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset(destination + length, 0, size - length);
|
||||||
|
return memcpy(destination, source, length);
|
||||||
|
}
|
||||||
|
}
|
18
src/tales/dprint.c
Normal file
18
src/tales/dprint.c
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include <internals/tales.h>
|
||||||
|
#include <internals/stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
dprint()
|
||||||
|
Prints a formatted string. Works the same as printf().
|
||||||
|
*/
|
||||||
|
void dprint(int x, int y, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
__printf(0, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
dtext(__stdio_buffer, x, y);
|
||||||
|
}
|
18
src/tales/gprint.c
Normal file
18
src/tales/gprint.c
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include <internals/tales.h>
|
||||||
|
#include <internals/stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
gprint()
|
||||||
|
Prints a formatted string. Works the same as printf().
|
||||||
|
*/
|
||||||
|
void gprint(int x, int y, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
__printf(0, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
gtext(__stdio_buffer, x, y);
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue