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:
2026-07-10 22:11:01 +03:00
parent c9ac0999fd
commit 9f8aa6fc28
16 changed files with 130 additions and 55 deletions
+6 -2
View File
@@ -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.
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
1 # Эталон размеров _CODE (байт); обновление: python3 toolchain/size_check.py --update
2 accfill
3 argv
4 assrtest
5 attrprob
6 banked
7 bankedbg
8 banklocl
9 banktest
10 bios_text bgi_img
11 bgitest
12 bios_text
13 cat
14 cblstream
15 cbltest
16 cblwav
17 conio
18 conio2
19 dec_test
20 errno
21 fbench
22 fdmax
23 filetest
24 gets
25 gfx_dbuf
26 gfx_demo
27 hello
28 hello2
29 irqtest
30 ls
31 malloc
32 mdview
33 mdview2
34 mem_test
35 mouse
36 openenv
37 ptime
38 rt_test
39 seek
40 simple
41 solidt
42 stattest
43 stdlib
44 stest2
45 strtest
46 text_palette
47 timedir
48 winrest
+53 -28
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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;
} }
+4
View File
@@ -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))
+2
View File
@@ -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;
+4
View File
@@ -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
+2
View File
@@ -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;
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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;
} }
+4
View File
@@ -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
View File
@@ -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;