libc: две версии библиотеки — sprinter.lib (fast) / sprinter_safe.lib
Симметрично libbgi (bgi256/bgi256_safe): fast = -DLIBC_NOCHECK, дефолт sprinter-cc; safe линкуется по --safe (флаг уже существовал). Под LIBC_NOCHECK вырезаны ТОЛЬКО параметр-валидации: - fgetc/fputc: NULL-check в горячей asm-обёртке (~11Т на каждый байт); - fgets/fputs/fread/fwrite: NULL ptr/fp и EBADF на неверное направление потока; ftell/fseek/ungetc/fclose: NULL fp; cputs: NULL s. НЕ тронуты: критичный _fd_guard (9-й OPEN вешает DSS — в обеих версиях), функциональная маршрутизация (консоль/направление/hold), cold-path валидации (fopen/cbl_open/irq/settextmode — экономии ноль). libc/Makefile — dual-build по образцу libbgi (build/fast + build/safe, общий стейл-контроль). Корневой Makefile: в TESTS добавлены bgitest, bgi_img, accfill, cblstream — раньше не собирались корневым make и выпадали из size-check при чистой пересборке. Дельты fast vs старая (safe-семантика): filetest -481, fbench -384, solidt -180, errno -71, остальные -3..-9; роста нет. Проверено в MAME: filetest fast и safe (--safe, sprinter_safe.lib) — прогоны идентичны. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,13 +7,17 @@ Target-слой SDCC 4.5 (z80) для компьютера Sprinter Sp2000: crt0
|
|||||||
|
|
||||||
```
|
```
|
||||||
make # tools + lib + libbgi + все тесты (45) + examples
|
make # tools + lib + libbgi + все тесты (45) + examples
|
||||||
make -C libc # только libc → lib/sprinter.lib
|
make -C libc # только libc → lib/sprinter.lib (fast) + sprinter_safe.lib
|
||||||
make -C libbgi # только BGI → lib/bgi256.lib (и bgi16.lib в Фазе 2)
|
make -C libbgi # только BGI → lib/bgi256.lib (fast) + bgi256_safe.lib
|
||||||
make floppy # упаковать все .exe в mame/v306/IMG/mc.img
|
make floppy # упаковать все .exe в mame/v306/IMG/mc.img
|
||||||
make size-check # размерный регресс: _CODE vs docs/size_baseline.tsv
|
make size-check # размерный регресс: _CODE vs docs/size_baseline.tsv
|
||||||
make size-baseline # принять текущие размеры эталоном
|
make size-baseline # принять текущие размеры эталоном
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Обе библиотеки собираются в двух вариантах: fast (дефолт; `-D*_NOCHECK` —
|
||||||
|
параметр-валидации вырезаны) и safe (линкуется по `sprinter-cc --safe`).
|
||||||
|
Критичные гарды (напр. _fd_guard — 9-й OPEN вешает DSS) — в ОБОИХ.
|
||||||
|
|
||||||
Графика (BGI) — отдельная библиотека libbgi/ (см. ниже). Программа,
|
Графика (BGI) — отдельная библиотека libbgi/ (см. ниже). Программа,
|
||||||
использующая graphics.h, собирается с `--gfx 256` (или `--gfx 16` в
|
использующая graphics.h, собирается с `--gfx 256` (или `--gfx 16` в
|
||||||
Фазе 2): sprinter-cc подлинкует lib/bgi256.lib и добавит -I libbgi/include.
|
Фазе 2): sprinter-cc подлинкует lib/bgi256.lib и добавит -I libbgi/include.
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
TESTS := hello hello2 simple banked bankedbg banktest strtest cat seek \
|
TESTS := hello hello2 simple banked bankedbg banktest strtest cat seek \
|
||||||
malloc mem_test argv errno rt_test openenv ls conio conio2 \
|
malloc mem_test argv errno rt_test openenv ls conio conio2 \
|
||||||
attrprob timedir mouse banklocl stdlib assrtest ptime stattest \
|
attrprob timedir mouse banklocl stdlib assrtest ptime stattest \
|
||||||
filetest fdmax fbench solidt irqtest cbltest cblwav dec_test gets stest2 winrest \
|
filetest fdmax fbench solidt irqtest cbltest cblwav cblstream dec_test gets stest2 winrest \
|
||||||
bios_text text_palette \
|
bios_text text_palette \
|
||||||
gfx_demo gfx_dbuf
|
gfx_demo gfx_dbuf bgitest bgi_img accfill
|
||||||
# gfx_d16 / gfx_text / gfx_mous — 16-цветные; убраны до Фазы 2 (bgi16.lib
|
# gfx_d16 / gfx_text / gfx_mous — 16-цветные; убраны до Фазы 2 (bgi16.lib
|
||||||
# ещё не собирается). Вернуть мигрированными на BGI --gfx 16.
|
# ещё не собирается). Вернуть мигрированными на BGI --gfx 16.
|
||||||
# Larger end-user applications under examples/.
|
# Larger end-user applications under examples/.
|
||||||
|
|||||||
+11
-2
@@ -146,6 +146,15 @@ case "$GFX_MODE" in
|
|||||||
*) echo "sprinter-cc: --gfx: ожидается 256 (или 16), дано: $GFX_MODE" >&2; exit 1;;
|
*) echo "sprinter-cc: --gfx: ожидается 256 (или 16), дано: $GFX_MODE" >&2; exit 1;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# ------- libc variant selection (--safe) --------------------------------------
|
||||||
|
# sprinter.lib — fast (LIBC_NOCHECK: параметр-валидации вырезаны);
|
||||||
|
# sprinter_safe.lib — с валидациями. Критичные гарды (_fd_guard) — в обеих.
|
||||||
|
LIBC_LD="-lsprinter"
|
||||||
|
if [[ "$SAFE_LIBS" -eq 1 ]] && [[ -f "$LIB_DIR/sprinter_safe.lib" ]]; then
|
||||||
|
LIBC_LD="-lsprinter_safe"
|
||||||
|
[[ $VERBOSE -eq 1 ]] && echo " libc: safe variant (lib/sprinter_safe.lib)"
|
||||||
|
fi
|
||||||
|
|
||||||
# ------- Resolve memory mode → CODE_LOC / DATA_LOC ---------------------------
|
# ------- Resolve memory mode → CODE_LOC / DATA_LOC ---------------------------
|
||||||
# tiny : CODE in W2 (0x8100), DATA auto after code (= W2)
|
# tiny : CODE in W2 (0x8100), DATA auto after code (= W2)
|
||||||
# small : CODE in W1 (0x4100), DATA in W2 (0x8000) — crt0 must alloc W2
|
# small : CODE in W1 (0x4100), DATA in W2 (0x8000) — crt0 must alloc W2
|
||||||
@@ -367,12 +376,12 @@ for f in "${LD_EXTRA[@]}"; do LINK_FLAGS+=("$f"); done
|
|||||||
if [[ $VERBOSE -eq 1 ]]; then
|
if [[ $VERBOSE -eq 1 ]]; then
|
||||||
run "$SDCC" "${LINK_FLAGS[@]}" -o "$IHX" \
|
run "$SDCC" "${LINK_FLAGS[@]}" -o "$IHX" \
|
||||||
"$CRT0_REL" "$HEAP_TOP_REL" "${USER_RELS[@]}" "${BANK_RELS[@]}" \
|
"$CRT0_REL" "$HEAP_TOP_REL" "${USER_RELS[@]}" "${BANK_RELS[@]}" \
|
||||||
"-L$LIB_DIR" "${GFX_LD[@]}" "-lsprinter"
|
"-L$LIB_DIR" "${GFX_LD[@]}" "$LIBC_LD"
|
||||||
else
|
else
|
||||||
# Drop the warning line + its two follow-up "Library:" lines.
|
# Drop the warning line + its two follow-up "Library:" lines.
|
||||||
run "$SDCC" "${LINK_FLAGS[@]}" -o "$IHX" \
|
run "$SDCC" "${LINK_FLAGS[@]}" -o "$IHX" \
|
||||||
"$CRT0_REL" "$HEAP_TOP_REL" "${USER_RELS[@]}" "${BANK_RELS[@]}" \
|
"$CRT0_REL" "$HEAP_TOP_REL" "${USER_RELS[@]}" "${BANK_RELS[@]}" \
|
||||||
"-L$LIB_DIR" "${GFX_LD[@]}" "-lsprinter" 2>&1 \
|
"-L$LIB_DIR" "${GFX_LD[@]}" "$LIBC_LD" 2>&1 \
|
||||||
| awk '
|
| awk '
|
||||||
/^\?ASlink-Warning-Definition of public symbol/ { skip = 3 }
|
/^\?ASlink-Warning-Definition of public symbol/ { skip = 3 }
|
||||||
skip > 0 { skip--; next }
|
skip > 0 { skip--; next }
|
||||||
|
|||||||
+21
-17
@@ -1,44 +1,48 @@
|
|||||||
# Эталон размеров _CODE (байт); обновление: python3 toolchain/size_check.py --update
|
# Эталон размеров _CODE (байт); обновление: python3 toolchain/size_check.py --update
|
||||||
|
accfill 3963
|
||||||
argv 3431
|
argv 3431
|
||||||
assrtest 3847
|
assrtest 3847
|
||||||
attrprob 4091
|
attrprob 4088
|
||||||
banked 1056
|
banked 1056
|
||||||
bankedbg 1067
|
bankedbg 1067
|
||||||
banklocl 4832
|
banklocl 4832
|
||||||
banktest 3767
|
banktest 3767
|
||||||
bios_text 4463
|
bgi_img 6572
|
||||||
|
bgitest 4053
|
||||||
|
bios_text 4460
|
||||||
cat 915
|
cat 915
|
||||||
|
cblstream 6277
|
||||||
cbltest 6407
|
cbltest 6407
|
||||||
cblwav 6486
|
cblwav 6486
|
||||||
conio 4634
|
conio 4631
|
||||||
conio2 3957
|
conio2 3954
|
||||||
dec_test 860
|
dec_test 860
|
||||||
errno 6216
|
errno 6145
|
||||||
fbench 9040
|
fbench 8656
|
||||||
fdmax 6337
|
fdmax 6328
|
||||||
filetest 11624
|
filetest 11143
|
||||||
gets 509
|
gets 509
|
||||||
gfx_dbuf 5378
|
gfx_dbuf 5378
|
||||||
gfx_demo 4286
|
gfx_demo 4286
|
||||||
hello 4170
|
hello 4167
|
||||||
hello2 4247
|
hello2 4244
|
||||||
irqtest 5881
|
irqtest 5881
|
||||||
ls 4919
|
ls 4916
|
||||||
malloc 4462
|
malloc 4462
|
||||||
mdview 19118
|
mdview 19115
|
||||||
mdview2 27036
|
mdview2 27033
|
||||||
mem_test 4558
|
mem_test 4558
|
||||||
mouse 4387
|
mouse 4384
|
||||||
openenv 6127
|
openenv 6127
|
||||||
ptime 5896
|
ptime 5896
|
||||||
rt_test 4906
|
rt_test 4906
|
||||||
seek 4177
|
seek 4177
|
||||||
simple 963
|
simple 960
|
||||||
solidt 12287
|
solidt 12107
|
||||||
stattest 7700
|
stattest 7700
|
||||||
stdlib 6643
|
stdlib 6643
|
||||||
stest2 3644
|
stest2 3644
|
||||||
strtest 1340
|
strtest 1340
|
||||||
text_palette 5039
|
text_palette 5036
|
||||||
timedir 5471
|
timedir 5471
|
||||||
winrest 4479
|
winrest 4479
|
||||||
|
|||||||
|
+53
-28
@@ -1,4 +1,4 @@
|
|||||||
# Build lib/sprinter.lib — the Sprinter target libc archive.
|
# Build lib/sprinter.lib + lib/sprinter_safe.lib — the Sprinter libc.
|
||||||
#
|
#
|
||||||
# libc/ — ядро библиотеки (БЕЗ графики; графика вынесена в libbgi/).
|
# libc/ — ядро библиотеки (БЕЗ графики; графика вынесена в libbgi/).
|
||||||
# Каждый .c под libc/<area>/ — отдельный .rel в архиве (1 публичная
|
# Каждый .c под libc/<area>/ — отдельный .rel в архиве (1 публичная
|
||||||
@@ -7,11 +7,18 @@
|
|||||||
# (heap для malloc). crt0-семейство НЕ в архиве — оно всегда явно
|
# (heap для malloc). crt0-семейство НЕ в архиве — оно всегда явно
|
||||||
# линкуется, не DCE-eligible. См. docs/libc-split-asm-cases.md.
|
# линкуется, не DCE-eligible. См. docs/libc-split-asm-cases.md.
|
||||||
#
|
#
|
||||||
# make build lib/sprinter.lib
|
# Две версии (симметрично libbgi: bgi256.lib / bgi256_safe.lib):
|
||||||
# make clean remove build/ + lib/sprinter.lib
|
# sprinter.lib = fast: -DLIBC_NOCHECK — параметр-валидации
|
||||||
|
# (NULL fp/buf, EBADF на неверное направление
|
||||||
|
# потока) ВЫРЕЗАНЫ; дефолт sprinter-cc.
|
||||||
|
# sprinter_safe.lib = safe: валидации включены; линкуется по --safe.
|
||||||
|
# КРИТИЧНЫЕ гарды (например _fd_guard — 9-й OPEN вешает DSS) живут в
|
||||||
|
# ОБЕИХ версиях и под LIBC_NOCHECK не попадают.
|
||||||
#
|
#
|
||||||
# Симметрично libbgi/Makefile: исходники и build/ рядом, результат
|
# make build обе библиотеки
|
||||||
# ложится в общий каталог lib/ (откуда его линкует sprinter-cc).
|
# make fast только lib/sprinter.lib
|
||||||
|
# make safe только lib/sprinter_safe.lib
|
||||||
|
# make clean remove build/ + обе библиотеки
|
||||||
|
|
||||||
PROJ_ROOT := $(abspath $(CURDIR)/..)
|
PROJ_ROOT := $(abspath $(CURDIR)/..)
|
||||||
SDCC_BIN := $(PROJ_ROOT)/third_party/sdcc/bin
|
SDCC_BIN := $(PROJ_ROOT)/third_party/sdcc/bin
|
||||||
@@ -35,55 +42,73 @@ LIBC_C := $(wildcard $(CURDIR)/*/*.c)
|
|||||||
# ассемблирует bank.s с нужным BANK_W1 флагом на каждый banked-build.
|
# ассемблирует bank.s с нужным BANK_W1 флагом на каждый banked-build.
|
||||||
RUNTIME_S := $(PROJ_ROOT)/runtime/heap.s
|
RUNTIME_S := $(PROJ_ROOT)/runtime/heap.s
|
||||||
|
|
||||||
LIBC_RELS := $(patsubst $(CURDIR)/%.c,$(BUILD)/%.rel,$(LIBC_C))
|
FAST_RELS := $(patsubst $(CURDIR)/%.c,$(BUILD)/fast/%.rel,$(LIBC_C)) \
|
||||||
RUNTIME_RELS := $(patsubst $(PROJ_ROOT)/runtime/%.s,$(BUILD)/%.rel,$(RUNTIME_S))
|
$(patsubst $(PROJ_ROOT)/runtime/%.s,$(BUILD)/fast/%.rel,$(RUNTIME_S))
|
||||||
|
SAFE_RELS := $(patsubst $(CURDIR)/%.c,$(BUILD)/safe/%.rel,$(LIBC_C)) \
|
||||||
|
$(patsubst $(PROJ_ROOT)/runtime/%.s,$(BUILD)/safe/%.rel,$(RUNTIME_S))
|
||||||
|
|
||||||
ALL_RELS := $(LIBC_RELS) $(RUNTIME_RELS)
|
KNOWN_RELS := $(FAST_RELS) $(SAFE_RELS)
|
||||||
KNOWN_RELS := $(ALL_RELS)
|
|
||||||
|
|
||||||
# Штамп списка модулей: обновляется при любом изменении состава
|
# Штамп списка модулей: обновляется при любом изменении состава
|
||||||
# (добавление/удаление/переименование исходника) — иначе удаление
|
# (добавление/удаление/переименование исходника) — иначе удаление
|
||||||
# исходника не триггерит перелинковку и stale .rel остаётся в архиве.
|
# исходника не триггерит перелинковку и stale .rel остаётся в архиве.
|
||||||
# Сразу сносим и архив: на exFAT (SAM8) гранулярность mtime грубая,
|
# Сразу сносим и архивы: на exFAT (SAM8) гранулярность mtime грубая,
|
||||||
# и «список изменился» через сравнение времён можно проглядеть.
|
# и «список изменился» через сравнение времён можно проглядеть.
|
||||||
MODLIST := $(BUILD)/.modules
|
MODLIST := $(BUILD)/.modules
|
||||||
ifneq ($(shell cat $(MODLIST) 2>/dev/null),$(KNOWN_RELS))
|
ifneq ($(shell cat $(MODLIST) 2>/dev/null),$(KNOWN_RELS))
|
||||||
_ := $(shell mkdir -p $(BUILD); echo "$(KNOWN_RELS)" > $(MODLIST); rm -f $(LIB))
|
_ := $(shell mkdir -p $(BUILD); echo "$(KNOWN_RELS)" > $(MODLIST); rm -f $(LIB_FAST) $(LIB_SAFE))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LIB_DIR := $(PROJ_ROOT)/lib
|
LIB_DIR := $(PROJ_ROOT)/lib
|
||||||
LIB := $(LIB_DIR)/sprinter.lib
|
LIB_FAST := $(LIB_DIR)/sprinter.lib
|
||||||
|
LIB_SAFE := $(LIB_DIR)/sprinter_safe.lib
|
||||||
|
|
||||||
all: $(LIB)
|
all: fast safe
|
||||||
|
|
||||||
# Pattern rule для C-модулей libc/<area>/file.c → build/<area>/file.rel
|
fast: $(LIB_FAST)
|
||||||
# (сохраняет путь io|mem|stdio внутри архива).
|
|
||||||
$(BUILD)/%.rel: $(CURDIR)/%.c
|
safe: $(LIB_SAFE)
|
||||||
|
|
||||||
|
# --- Fast: -DLIBC_NOCHECK (параметр-валидации выключены) ------------
|
||||||
|
$(BUILD)/fast/%.rel: $(CURDIR)/%.c
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
$(SDCC) $(CC_FLAGS) -DLIBC_NOCHECK -c -o $@ $<
|
||||||
|
|
||||||
|
$(BUILD)/fast/%.rel: $(PROJ_ROOT)/runtime/%.s
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
$(SDASZ80) -o $@ $<
|
||||||
|
|
||||||
|
# --- Safe: валидации включены ----------------------------------------
|
||||||
|
$(BUILD)/safe/%.rel: $(CURDIR)/%.c
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(SDCC) $(CC_FLAGS) -c -o $@ $<
|
$(SDCC) $(CC_FLAGS) -c -o $@ $<
|
||||||
|
|
||||||
# Runtime .s → .rel (runtime/ вне libc/, но heap.s бандлится в архив).
|
$(BUILD)/safe/%.rel: $(PROJ_ROOT)/runtime/%.s
|
||||||
$(BUILD)/%.rel: $(PROJ_ROOT)/runtime/%.s
|
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(SDASZ80) -o $@ $<
|
$(SDASZ80) -o $@ $<
|
||||||
|
|
||||||
# Archive — sdar rcs = replace/create/symtab. Перед упаковкой удаляем
|
# Archive — sdar rcs = replace/create/symtab. Перед упаковкой удаляем
|
||||||
# stale .rel: wildcard не знает об удалённых/переименованных исходниках,
|
# stale .rel: wildcard не знает об удалённых/переименованных исходниках,
|
||||||
# и осиротевший .rel из build/ иначе жил бы вечно.
|
# и осиротевший .rel из build/ иначе жил бы вечно.
|
||||||
$(LIB): $(ALL_RELS) $(MODLIST)
|
define PACK_LIB
|
||||||
@find $(BUILD) -name '*.rel' -print | sort > $(BUILD)/.have
|
@find $(BUILD)/$(1) -name '*.rel' -print | sort > $(BUILD)/.have_$(1)
|
||||||
@printf '%s\n' $(KNOWN_RELS) | sort > $(BUILD)/.want
|
@printf '%s\n' $(2) | sort > $(BUILD)/.want_$(1)
|
||||||
@comm -23 $(BUILD)/.have $(BUILD)/.want | while read f; do \
|
@comm -23 $(BUILD)/.have_$(1) $(BUILD)/.want_$(1) | while read f; do \
|
||||||
echo " stale: $$f (исходник удалён) — rm"; \
|
echo " stale: $$f (исходник удалён) — rm"; \
|
||||||
rm -f "$$f" "$${f%.rel}.asm" "$${f%.rel}.lst" "$${f%.rel}.sym"; \
|
rm -f "$$f" "$${f%.rel}.asm" "$${f%.rel}.lst" "$${f%.rel}.sym"; \
|
||||||
done
|
done
|
||||||
rm -f $@
|
rm -f $@
|
||||||
$(SDAR) -rcs $@ $(ALL_RELS)
|
$(SDAR) -rcs $@ $(2)
|
||||||
@echo
|
@echo " Built $@ with $(words $(2)) modules."
|
||||||
@echo " Built $@ with $(words $(ALL_RELS)) modules:"
|
endef
|
||||||
@$(SDAR) -t $@ | sed 's/^/ /'
|
|
||||||
|
$(LIB_FAST): $(FAST_RELS) $(MODLIST)
|
||||||
|
$(call PACK_LIB,fast,$(FAST_RELS))
|
||||||
|
|
||||||
|
$(LIB_SAFE): $(SAFE_RELS) $(MODLIST)
|
||||||
|
$(call PACK_LIB,safe,$(SAFE_RELS))
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD) $(LIB)
|
rm -rf $(BUILD) $(LIB_FAST) $(LIB_SAFE)
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all fast safe clean
|
||||||
|
|||||||
@@ -19,10 +19,12 @@ char cputs(const char *s) __naked
|
|||||||
__asm
|
__asm
|
||||||
;; HL = s на входе; возврат char → A.
|
;; HL = s на входе; возврат char → A.
|
||||||
|
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
;; NULL-check: cputs(NULL) → сразу вернуть 0.
|
;; NULL-check: cputs(NULL) → сразу вернуть 0.
|
||||||
ld a, h
|
ld a, h
|
||||||
or a, l
|
or a, l
|
||||||
ret z
|
ret z
|
||||||
|
#endif
|
||||||
|
|
||||||
push ix
|
push ix
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,12 @@
|
|||||||
|
|
||||||
int fclose(FILE *fp)
|
int fclose(FILE *fp)
|
||||||
{
|
{
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (fp->flags & (_F_CONIN | _F_CONOUT)) {
|
if (fp->flags & (_F_CONIN | _F_CONOUT)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,9 @@
|
|||||||
* пределах этого модуля). */
|
* пределах этого модуля). */
|
||||||
static int fgetc_slow(FILE *fp)
|
static int fgetc_slow(FILE *fp)
|
||||||
{
|
{
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
if (!fp) { errno = EBADF; return EOF; }
|
if (!fp) { errno = EBADF; return EOF; }
|
||||||
|
#endif
|
||||||
if (fp->hold != EOF) {
|
if (fp->hold != EOF) {
|
||||||
int c = fp->hold;
|
int c = fp->hold;
|
||||||
fp->hold = EOF;
|
fp->hold = EOF;
|
||||||
@@ -62,9 +64,11 @@ int fgetc(FILE *fp) __naked
|
|||||||
(void)fgetc_slow; /* используется из asm */
|
(void)fgetc_slow; /* используется из asm */
|
||||||
__asm
|
__asm
|
||||||
;; HL = fp.
|
;; HL = fp.
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
ld a, h
|
ld a, h
|
||||||
or a, l
|
or a, l
|
||||||
jr Z, _fg_slow ; NULL — C-путь выставит errno
|
jr Z, _fg_slow ; NULL — C-путь выставит errno
|
||||||
|
#endif
|
||||||
push hl
|
push hl
|
||||||
pop iy ; IY = fp (IY — scratch в __sdcccall(1))
|
pop iy ; IY = fp (IY — scratch в __sdcccall(1))
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ static uint16_t fgets_scan(uint8_t *dst, const uint8_t *src,
|
|||||||
|
|
||||||
char *fgets(char *buf, int n, FILE *fp)
|
char *fgets(char *buf, int n, FILE *fp)
|
||||||
{
|
{
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
if (!buf || n < 1 || !fp) return NULL;
|
if (!buf || n < 1 || !fp) return NULL;
|
||||||
|
#endif
|
||||||
uint8_t *dst = (uint8_t *)buf;
|
uint8_t *dst = (uint8_t *)buf;
|
||||||
int space = n - 1;
|
int space = n - 1;
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,9 @@
|
|||||||
/* Медленный путь; зовётся из asm-обёртки. */
|
/* Медленный путь; зовётся из asm-обёртки. */
|
||||||
static int fputc_slow(int c, FILE *fp)
|
static int fputc_slow(int c, FILE *fp)
|
||||||
{
|
{
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
if (!fp) { errno = EBADF; return EOF; }
|
if (!fp) { errno = EBADF; return EOF; }
|
||||||
|
#endif
|
||||||
if (fp->flags & _F_CONOUT) {
|
if (fp->flags & _F_CONOUT) {
|
||||||
putchar(c);
|
putchar(c);
|
||||||
return (int)(uint8_t)c;
|
return (int)(uint8_t)c;
|
||||||
@@ -63,9 +65,11 @@ int fputc(int c, FILE *fp) __naked
|
|||||||
(void)fputc_slow; /* используется из asm */
|
(void)fputc_slow; /* используется из asm */
|
||||||
__asm
|
__asm
|
||||||
;; HL = c, DE = fp.
|
;; HL = c, DE = fp.
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
ld a, d
|
ld a, d
|
||||||
or a, e
|
or a, e
|
||||||
jr Z, _fp_slow ; NULL — C-путь выставит errno
|
jr Z, _fp_slow ; NULL — C-путь выставит errno
|
||||||
|
#endif
|
||||||
push de
|
push de
|
||||||
pop iy ; IY = fp
|
pop iy ; IY = fp
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,9 @@
|
|||||||
|
|
||||||
int fputs(const char *s, FILE *fp)
|
int fputs(const char *s, FILE *fp)
|
||||||
{
|
{
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
if (!fp || !s) return EOF;
|
if (!fp || !s) return EOF;
|
||||||
|
#endif
|
||||||
size_t n = strlen(s);
|
size_t n = strlen(s);
|
||||||
if (n == 0) return 0;
|
if (n == 0) return 0;
|
||||||
return fwrite(s, 1, n, fp) == n ? 0 : EOF;
|
return fwrite(s, 1, n, fp) == n ? 0 : EOF;
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *fp)
|
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *fp)
|
||||||
{
|
{
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
if (!ptr || !fp) return 0;
|
if (!ptr || !fp) return 0;
|
||||||
|
#endif
|
||||||
if (size == 0 || nmemb == 0) return 0;
|
if (size == 0 || nmemb == 0) return 0;
|
||||||
|
|
||||||
uint8_t *p = (uint8_t *)ptr;
|
uint8_t *p = (uint8_t *)ptr;
|
||||||
@@ -39,7 +41,9 @@ size_t fread(void *ptr, size_t size, size_t nmemb, FILE *fp)
|
|||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
if (!(fp->flags & _F_READ)) { errno = EBADF; return 0; }
|
if (!(fp->flags & _F_READ)) { errno = EBADF; return 0; }
|
||||||
|
#endif
|
||||||
if (fp->flags & _F_DIROUT) {
|
if (fp->flags & _F_DIROUT) {
|
||||||
if (_file_sync(fp)) return 0; /* сброс накопленной записи */
|
if (_file_sync(fp)) return 0; /* сброс накопленной записи */
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -14,7 +14,10 @@
|
|||||||
|
|
||||||
int fseek(FILE *fp, long off, int whence)
|
int fseek(FILE *fp, long off, int whence)
|
||||||
{
|
{
|
||||||
if (!fp || (fp->flags & (_F_CONIN | _F_CONOUT))) {
|
#ifndef LIBC_NOCHECK
|
||||||
|
if (!fp) { errno = EBADF; return -1; }
|
||||||
|
#endif
|
||||||
|
if (fp->flags & (_F_CONIN | _F_CONOUT)) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -12,7 +12,10 @@
|
|||||||
|
|
||||||
long ftell(FILE *fp)
|
long ftell(FILE *fp)
|
||||||
{
|
{
|
||||||
if (!fp || (fp->flags & (_F_CONIN | _F_CONOUT))) {
|
#ifndef LIBC_NOCHECK
|
||||||
|
if (!fp) { errno = EBADF; return -1L; }
|
||||||
|
#endif
|
||||||
|
if (fp->flags & (_F_CONIN | _F_CONOUT)) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1L;
|
return -1L;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@
|
|||||||
|
|
||||||
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp)
|
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp)
|
||||||
{
|
{
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
if (!ptr || !fp) return 0;
|
if (!ptr || !fp) return 0;
|
||||||
|
#endif
|
||||||
if (size == 0 || nmemb == 0) return 0;
|
if (size == 0 || nmemb == 0) return 0;
|
||||||
|
|
||||||
const uint8_t *p = (const uint8_t *)ptr;
|
const uint8_t *p = (const uint8_t *)ptr;
|
||||||
@@ -30,7 +32,9 @@ size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp)
|
|||||||
}
|
}
|
||||||
return nmemb;
|
return nmemb;
|
||||||
}
|
}
|
||||||
|
#ifndef LIBC_NOCHECK
|
||||||
if (!(fp->flags & _F_WRITE)) { errno = EBADF; return 0; }
|
if (!(fp->flags & _F_WRITE)) { errno = EBADF; return 0; }
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!(fp->flags & _F_DIROUT)) {
|
if (!(fp->flags & _F_DIROUT)) {
|
||||||
if (_file_sync(fp)) return 0; /* откат readahead/hold */
|
if (_file_sync(fp)) return 0; /* откат readahead/hold */
|
||||||
|
|||||||
+4
-1
@@ -10,7 +10,10 @@
|
|||||||
|
|
||||||
int ungetc(int c, FILE *fp)
|
int ungetc(int c, FILE *fp)
|
||||||
{
|
{
|
||||||
if (!fp || c == EOF) return EOF;
|
#ifndef LIBC_NOCHECK
|
||||||
|
if (!fp) return EOF;
|
||||||
|
#endif
|
||||||
|
if (c == EOF) return EOF; /* семантика стандарта */
|
||||||
if (fp->hold != EOF) return EOF; /* место занято */
|
if (fp->hold != EOF) return EOF; /* место занято */
|
||||||
if (fp->flags & _F_CONOUT) return EOF;
|
if (fp->flags & _F_CONOUT) return EOF;
|
||||||
if (!(fp->flags & (_F_READ | _F_CONIN))) return EOF;
|
if (!(fp->flags & (_F_READ | _F_CONIN))) return EOF;
|
||||||
|
|||||||
Reference in New Issue
Block a user