mdview2: оптимизация размера — exe 28215 → 25616 (−2599 Б)

Раунд 1 (−1411): --max-allocs 100000 в Makefile (−848 кода) + снятие
всех нулевых инициализаторов file-scope переменных (_INITIALIZER
583→24; _DATA теперь зануляется в crt0).

Раунд 2 (−1188, индексатор 11019→9839): дедупликации в mdview2_index.c:
- classify_line: копия HR-проверки → вызов is_hr_raw;
- next_line() поверх row_end() вместо 9 копий «домотать до \n»;
- inline_marker: emph_to_attr(ls, base) вычисляется один раз (at);
- set_{nowrap,blank,code,hscroll}_cur → set_cur_flags(mask): строка
  code-блока делает один idx_put вместо трёх.

Проверено в MAME (README/UTF8TEST: маркеры, списки, цитаты, таблицы,
code-блоки, F8).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-04 21:15:43 +03:00
parent 961cfb786d
commit ffd179e064
5 changed files with 95 additions and 118 deletions
+38 -38
View File
@@ -101,15 +101,15 @@ static const uint8_t md_pallete[16 * 4] = {
/* MAX_CACHE_LINE_LEN — в mdview2.h (буфер ячеек g_cells живёт в mdview2_index.c). */
#define MAX_CACHE_CONTENT_PAGES 40u /* кап контента на набор: 40 * 16 КБ = 640 КБ (80 на оба набора) */
static uint8_t cache_dir_blk = 0;
static uint8_t cache_dir_pages = 0;
static uint8_t cache_dir_phys[MAX_CACHE_DIR_PAGES] = {0};
static uint8_t cache_dir_blk;
static uint8_t cache_dir_pages;
static uint8_t cache_dir_phys[MAX_CACHE_DIR_PAGES];
static uint8_t cache_content_blk[MAX_CACHE_CONTENT_PAGES] = {0}; /* id блока на каждую выделенную страницу */
static uint8_t cache_content_phys[MAX_CACHE_CONTENT_PAGES] = {0};
static uint8_t cache_content_n_pages = 0; /* сколько страниц уже выделено */
static uint8_t cache_cur_page_idx = 0; /* индекс текущей страницы записи в cache_content_phys */
static uint16_t cache_cur_off = 0; /* текущее смещение записи в этой странице */
static uint8_t cache_content_blk[MAX_CACHE_CONTENT_PAGES]; /* id блока на каждую выделенную страницу */
static uint8_t cache_content_phys[MAX_CACHE_CONTENT_PAGES];
static uint8_t cache_content_n_pages; /* сколько страниц уже выделено */
static uint8_t cache_cur_page_idx; /* индекс текущей страницы записи в cache_content_phys */
static uint16_t cache_cur_off; /* текущее смещение записи в этой странице */
/* Доступ к директории рендер-кэша — тот же приём, что у idx_get/idx_put. */
void cache_dir_get(uint16_t idx, cache_rec_t *r)
@@ -175,41 +175,41 @@ void cache_commit(uint8_t page, uint16_t off, const void *buf, uint16_t len)
/* emph_to_attr определена ниже (рядом с inline-логикой), нужна в inline_scan. */
/* emph_to_attr — в mdview2_index.c. */
uint16_t n_lines = 0; /* extern: всего строк в индексе текущего набора */
uint16_t max_lines = 0; /* extern: ёмкость индекса: index_pages * 2048 */
uint16_t top_line = 0; /* extern: верхняя видимая строка */
uint32_t file_size = 0; /* extern: размер активного буфера документа */
static uint8_t file_blk = 0;
static uint8_t file_pages = 0;
static uint8_t file_phys[MAX_PAGES] = {0};
uint8_t index_blk = 0; /* extern: дескриптор EMM-блока индекса */
uint8_t index_pages = 0; /* */
uint8_t index_phys[MAX_INDEX_PAGES] = {0}; /* extern: физ. страницы индекса */
uint8_t index_truncated = 0; /* выставляется при исчерпании ёмкости индекса */
uint8_t g_file_clamped = 0; /* extern: файл >256 КБ обрезан до MAX_FILE при загрузке */
uint16_t n_lines; /* extern: всего строк в индексе текущего набора */
uint16_t max_lines; /* extern: ёмкость индекса: index_pages * 2048 */
uint16_t top_line; /* extern: верхняя видимая строка */
uint32_t file_size; /* extern: размер активного буфера документа */
static uint8_t file_blk;
static uint8_t file_pages;
static uint8_t file_phys[MAX_PAGES];
uint8_t index_blk; /* extern: дескриптор EMM-блока индекса */
uint8_t index_pages; /* */
uint8_t index_phys[MAX_INDEX_PAGES]; /* extern: физ. страницы индекса */
uint8_t index_truncated; /* выставляется при исчерпании ёмкости индекса */
uint8_t g_file_clamped; /* extern: файл >256 КБ обрезан до MAX_FILE при загрузке */
/* cur_seg_off/cur_rec (near-состояние индексатора) — в mdview2_index.c. */
uint8_t cur_page = 0xFF; /* extern: 0xFF = в W3 ещё не показана ни одна страница (extern: кодек инвалидирует) */
uint8_t viewport_x = 0; /* extern: горизонтальный сдвиг для nowrap-строк */
char filename[64] = {0}; /* extern: статус-бар */
uint8_t viewport_x; /* extern: горизонтальный сдвиг для nowrap-строк */
char filename[64]; /* extern: статус-бар */
/* Прогрессивная загрузка: рисуем первый экран и пускаем скролл, пока
* index_lines() ещё досканирует файл (кооперативно, без прерываний). */
uint8_t g_view = VIEW_MD; /* extern: активный режим просмотра (существует даже когда доступен только MD режим) */
#if WITH_RAW
uint8_t g_ready = 0; /* extern: 1 когда первичный документ построен — F2 (RAW) рабочий */
uint8_t g_ready; /* extern: 1 когда первичный документ построен — F2 (RAW) рабочий */
static uint8_t g_raw_last = VIEW_RAW_WRAP; /* последний под-режим RAW (возврат по F2) */
#endif
uint8_t g_loading = 0; /* extern: 1 во время index_lines() */
static uint8_t g_first_drawn = 0; /* первый экран уже нарисован */
uint8_t g_f8_enabled = 0; /* extern: можно ли сейчас переключать кодировку */
static uint8_t g_utf_failed = 0; /* UTF-8 набор не удалось построить (нет EMM) — пропускаем UTF-8 в цикле F8 */
uint8_t g_abort = 0; /* extern: F10/Esc во время загрузки → прервать индексацию */
static uint16_t g_last_prog = 0; /* n_lines на последнем обновлении статуса */
uint8_t g_loading; /* extern: 1 во время index_lines() */
static uint8_t g_first_drawn; /* первый экран уже нарисован */
uint8_t g_f8_enabled; /* extern: можно ли сейчас переключать кодировку */
static uint8_t g_utf_failed; /* UTF-8 набор не удалось построить (нет EMM) — пропускаем UTF-8 в цикле F8 */
uint8_t g_abort; /* extern: F10/Esc во время загрузки → прервать индексацию */
static uint16_t g_last_prog; /* n_lines на последнем обновлении статуса */
/* Кодировки (ENC_*) и g_encoding — в mdview2.h / mdview2_enc.c. */
const uint8_t *g_remap = 0; /* extern: активная таблица ремапа (CP1251/KOI8), 0 = без ремапа (CP866)*/
uint8_t g_scratch_phys = 0; /* extern: EMM-страница под ремап-буфер строки для win_rest */
const uint8_t *g_remap; /* extern: активная таблица ремапа (CP1251/KOI8), 0 = без ремапа (CP866)*/
uint8_t g_scratch_phys; /* extern: EMM-страница под ремап-буфер строки для win_rest */
/* UTF-8 набор (utf_blk/utf_pages/utf_phys/utf_size/utf_avail, конвертер и его
* состояние) — в mdview2_enc.c; разделяемые символы и API — в mdview2.h.
@@ -218,10 +218,10 @@ uint8_t g_scratch_phys = 0; /* extern: EMM-страни
/* Снимок исходного (8-битного) файлового буфера — набор DOC_8BIT читает его
* как есть, набор DOC_UTF8 читает utf_phys. */
static uint8_t orig_file_blk = 0;
uint8_t orig_file_pages = 0; /* extern: читает кодек (utf_alloc) */
uint32_t orig_file_size = 0; /* extern: читает кодек (utf_convert_more) */
uint8_t orig_file_phys[MAX_PAGES] = {0}; /* extern: читает кодек (cv_read) */
static uint8_t orig_file_blk;
uint8_t orig_file_pages; /* extern: читает кодек (utf_alloc) */
uint32_t orig_file_size; /* extern: читает кодек (utf_convert_more) */
uint8_t orig_file_phys[MAX_PAGES]; /* extern: читает кодек (cv_read) */
/* ----------------- Два сосуществующих набора индекс/кэш -----------------
* DOC_8BIT — исходные байты (CP866/CP1251/KOI8R, различаются ремапом на
@@ -250,9 +250,9 @@ typedef struct {
#define DOC_8BIT 0
#define DOC_UTF8 1
static docset_t g_doc[2] = {{0}, {0}}; /* ОБЯЗАТЕЛЬНО инициализировать: built=0 для обоих
* (SDCC z80 не обнуляет неинициализированные статики
* надёжно — см. memory/sdcc_static_storage_gotcha) */
static docset_t g_doc[2]; /* built=0 для обоих: _DATA зануляется в crt0 gsinit
* (с 2026-07-04), явный {0}-инициализатор больше
* не нужен — он стоил ~260 байт _INITIALIZER */
static uint8_t g_active_doc = DOC_8BIT; /* какой набор сейчас в живых глобалах */
static uint8_t g_disp_doc = DOC_8BIT; /* какой набор показан пользователю */