Help compiler integrated with DVX.
This commit is contained in:
parent
66952306df
commit
7157f97c28
8 changed files with 410 additions and 209 deletions
2
Makefile
2
Makefile
|
|
@ -66,7 +66,7 @@ compile-help:
|
||||||
apps/dvxhelp/help.dhs
|
apps/dvxhelp/help.dhs
|
||||||
$(HLPC) -o bin/apps/kpunch/progman/dvxhelp.hlp \
|
$(HLPC) -o bin/apps/kpunch/progman/dvxhelp.hlp \
|
||||||
--html docs/dvx_system_reference.html \
|
--html docs/dvx_system_reference.html \
|
||||||
-i assets \
|
-i core \
|
||||||
$(SYSTEM_DHS) \
|
$(SYSTEM_DHS) \
|
||||||
$$(find widgets -name "*.dhs" ! -path "widgets/wgtsys.dhs" | sort)
|
$$(find widgets -name "*.dhs" ! -path "widgets/wgtsys.dhs" | sort)
|
||||||
$(HLPC) -o bin/apps/kpunch/dvxbasic/dvxbasic.hlp \
|
$(HLPC) -o bin/apps/kpunch/dvxbasic/dvxbasic.hlp \
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
# DVX System Help configuration
|
# DVX System Help configuration
|
||||||
# Compiled into DVXHELP.HLP in this directory
|
# Compiled into DVXHELP.HLP in this directory
|
||||||
output = DVXHELP.HLP
|
output = DVXHELP.HLP
|
||||||
|
imagedir = LIBS/KPUNCH/LIBDVX
|
||||||
source = LIBS/*.DHS
|
source = LIBS/*.DHS
|
||||||
source = WIDGETS/*.DHS
|
source = WIDGETS/*.DHS
|
||||||
|
|
|
||||||
BIN
core/help.png
(Stored with Git LFS)
Normal file
BIN
core/help.png
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -18,7 +18,7 @@ BINDIR = ../bin
|
||||||
|
|
||||||
SRCS = loaderMain.c
|
SRCS = loaderMain.c
|
||||||
OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(SRCS))
|
OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(SRCS))
|
||||||
POBJS = $(POBJDIR)/dvxPlatformDos.o $(POBJDIR)/dvxPrefs.o
|
POBJS = $(POBJDIR)/dvxPlatformDos.o $(POBJDIR)/dvxPrefs.o $(OBJDIR)/dvxhlpc.o
|
||||||
TARGET = $(BINDIR)/dvx.exe
|
TARGET = $(BINDIR)/dvx.exe
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
@ -40,6 +40,9 @@ $(POBJDIR)/dvxPlatformDos.o: ../core/platform/dvxPlatformDos.c | $(POBJDIR)
|
||||||
$(POBJDIR)/dvxPrefs.o: ../core/dvxPrefs.c | $(POBJDIR)
|
$(POBJDIR)/dvxPrefs.o: ../core/dvxPrefs.c | $(POBJDIR)
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(OBJDIR)/dvxhlpc.o: ../tools/dvxhlpc.c ../tools/hlpcCompile.h ../apps/dvxhelp/hlpformat.h | $(OBJDIR)
|
||||||
|
$(CC) $(CFLAGS) -DHLPC_NO_MAIN -c -o $@ ../tools/dvxhlpc.c
|
||||||
|
|
||||||
$(OBJDIR):
|
$(OBJDIR):
|
||||||
mkdir -p $(OBJDIR)
|
mkdir -p $(OBJDIR)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "dvxPlat.h"
|
#include "dvxPlat.h"
|
||||||
#include "dvxPrefs.h"
|
#include "dvxPrefs.h"
|
||||||
|
#include "../tools/hlpcCompile.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
@ -36,7 +37,6 @@
|
||||||
#define WIDGET_DIR "WIDGETS"
|
#define WIDGET_DIR "WIDGETS"
|
||||||
#define LOG_PATH "dvx.log"
|
#define LOG_PATH "dvx.log"
|
||||||
#define INI_PATH "CONFIG/DVX.INI"
|
#define INI_PATH "CONFIG/DVX.INI"
|
||||||
#define HLPC_PATH "SYSTEM/DVXHLPC.EXE"
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Splash screen (delegates to platformSplash* in dvxPlatformDos.c)
|
// Splash screen (delegates to platformSplash* in dvxPlatformDos.c)
|
||||||
|
|
@ -119,7 +119,6 @@ typedef struct {
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
static bool allDepsLoaded(const ModuleT *mod, const ModuleT *mods);
|
static bool allDepsLoaded(const ModuleT *mod, const ModuleT *mods);
|
||||||
static int32_t countHcfFilesRecurse(const char *dirPath);
|
|
||||||
static void extractBaseName(const char *path, const char *ext, char *out, int32_t outSize);
|
static void extractBaseName(const char *path, const char *ext, char *out, int32_t outSize);
|
||||||
static void *findSymbol(void **handles, const char *symbol);
|
static void *findSymbol(void **handles, const char *symbol);
|
||||||
static void freeMods(ModuleT *mods);
|
static void freeMods(ModuleT *mods);
|
||||||
|
|
@ -504,68 +503,8 @@ bool platformGlobMatch(const char *pattern, const char *name) {
|
||||||
// excludes matching files. The loader expands these by scanning
|
// excludes matching files. The loader expands these by scanning
|
||||||
// directories and matching filenames.
|
// directories and matching filenames.
|
||||||
|
|
||||||
// Recursively count .hcf files under the given directory
|
// Collect matching filenames into an stb_ds array of strdup'd paths.
|
||||||
static int32_t countHcfFilesRecurse(const char *dirPath) {
|
static void collectGlobFiles(char ***outFiles, const char *pattern, const char *excludePattern) {
|
||||||
DIR *dir = opendir(dirPath);
|
|
||||||
|
|
||||||
if (!dir) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char **names = NULL;
|
|
||||||
struct dirent *ent;
|
|
||||||
|
|
||||||
while ((ent = readdir(dir)) != NULL) {
|
|
||||||
if (ent->d_name[0] == '.') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
arrput(names, strdup(ent->d_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
int32_t count = 0;
|
|
||||||
int32_t nEntries = (int32_t)arrlen(names);
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < nEntries; i++) {
|
|
||||||
char fullPath[DVX_MAX_PATH];
|
|
||||||
snprintf(fullPath, sizeof(fullPath), "%s%c%s", dirPath, DVX_PATH_SEP, names[i]);
|
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (stat(fullPath, &st) == 0) {
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
|
||||||
count += countHcfFilesRecurse(fullPath);
|
|
||||||
} else {
|
|
||||||
int32_t nameLen = (int32_t)strlen(names[i]);
|
|
||||||
|
|
||||||
if (nameLen > 4 && strcasecmp(names[i] + nameLen - 4, ".hcf") == 0) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(names[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
arrfree(names);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Count .hcf files under APPS/
|
|
||||||
static int32_t countHcfFiles(void) {
|
|
||||||
return countHcfFilesRecurse("APPS");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Process a single .hcf file: parse it and invoke the compiler.
|
|
||||||
#define HELP_RESP_FILE "SYSTEM/HLPFILES.TMP"
|
|
||||||
|
|
||||||
// Write matching filenames to the response file (one per line).
|
|
||||||
static void writeGlobToResp(FILE *resp, const char *pattern, const char *excludePattern) {
|
|
||||||
// Split pattern into directory and filename glob
|
|
||||||
char dirPart[DVX_MAX_PATH];
|
char dirPart[DVX_MAX_PATH];
|
||||||
const char *globPart = NULL;
|
const char *globPart = NULL;
|
||||||
|
|
||||||
|
|
@ -616,10 +555,10 @@ static void writeGlobToResp(FILE *resp, const char *pattern, const char *exclude
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
char subPattern[DVX_MAX_PATH];
|
char subPattern[DVX_MAX_PATH];
|
||||||
snprintf(subPattern, sizeof(subPattern), "%s%c%s", fullPath, DVX_PATH_SEP, globPart);
|
snprintf(subPattern, sizeof(subPattern), "%s%c%s", fullPath, DVX_PATH_SEP, globPart);
|
||||||
writeGlobToResp(resp, subPattern, excludePattern);
|
collectGlobFiles(outFiles, subPattern, excludePattern);
|
||||||
} else if (platformGlobMatch(globPart, names[i])) {
|
} else if (platformGlobMatch(globPart, names[i])) {
|
||||||
if (!excludePattern || !platformGlobMatch(excludePattern, names[i])) {
|
if (!excludePattern || !platformGlobMatch(excludePattern, names[i])) {
|
||||||
fprintf(resp, "%s\n", fullPath);
|
arrput(*outFiles, strdup(fullPath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -631,6 +570,80 @@ static void writeGlobToResp(FILE *resp, const char *pattern, const char *exclude
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Progress callback for hlpcCompile — updates the splash progress bar.
|
||||||
|
static void hlpcProgressCallback(void *ctx, int32_t current, int32_t total) {
|
||||||
|
(void)ctx;
|
||||||
|
(void)total;
|
||||||
|
(void)current;
|
||||||
|
sSplashLoaded++;
|
||||||
|
splashUpdateProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Count input files for a single .hcf config (for progress total calculation).
|
||||||
|
static int32_t countHcfInputFiles(const char *hcfPath) {
|
||||||
|
FILE *f = fopen(hcfPath, "r");
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char **files = NULL;
|
||||||
|
char line[512];
|
||||||
|
|
||||||
|
while (fgets(line, (int)sizeof(line), f)) {
|
||||||
|
int32_t len = (int32_t)strlen(line);
|
||||||
|
|
||||||
|
while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r' || line[len - 1] == ' ')) {
|
||||||
|
line[--len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line[0] == '#' || line[0] == '\0') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncasecmp(line, "source", 6) == 0) {
|
||||||
|
const char *p = line + 6;
|
||||||
|
|
||||||
|
while (*p == ' ' || *p == '=') { p++; }
|
||||||
|
|
||||||
|
char pattern[DVX_MAX_PATH] = {0};
|
||||||
|
char exclude[DVX_MAX_PATH] = {0};
|
||||||
|
const char *bang = strchr(p, '!');
|
||||||
|
|
||||||
|
if (bang) {
|
||||||
|
int32_t patLen = (int32_t)(bang - p);
|
||||||
|
|
||||||
|
while (patLen > 0 && p[patLen - 1] == ' ') { patLen--; }
|
||||||
|
|
||||||
|
memcpy(pattern, p, patLen);
|
||||||
|
pattern[patLen] = '\0';
|
||||||
|
bang++;
|
||||||
|
|
||||||
|
while (*bang == ' ') { bang++; }
|
||||||
|
|
||||||
|
snprintf(exclude, sizeof(exclude), "%s", bang);
|
||||||
|
} else {
|
||||||
|
snprintf(pattern, sizeof(pattern), "%s", p);
|
||||||
|
}
|
||||||
|
|
||||||
|
collectGlobFiles(&files, pattern, exclude[0] ? exclude : NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
int32_t count = (int32_t)arrlen(files);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < count; i++) {
|
||||||
|
free(files[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
arrfree(files);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void processHcf(const char *hcfPath, const char *hcfDir) {
|
static void processHcf(const char *hcfPath, const char *hcfDir) {
|
||||||
FILE *f = fopen(hcfPath, "r");
|
FILE *f = fopen(hcfPath, "r");
|
||||||
|
|
||||||
|
|
@ -639,17 +652,8 @@ static void processHcf(const char *hcfPath, const char *hcfDir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
char outputFile[DVX_MAX_PATH] = {0};
|
char outputFile[DVX_MAX_PATH] = {0};
|
||||||
|
char imgDir[DVX_MAX_PATH] = {0};
|
||||||
// Write matching source files to a response file
|
char **inputFiles = NULL;
|
||||||
FILE *resp = fopen(HELP_RESP_FILE, "w");
|
|
||||||
|
|
||||||
if (!resp) {
|
|
||||||
fclose(f);
|
|
||||||
dvxLog("helpRecompile: cannot create %s", HELP_RESP_FILE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasFiles = false;
|
|
||||||
char line[512];
|
char line[512];
|
||||||
|
|
||||||
while (fgets(line, (int)sizeof(line), f)) {
|
while (fgets(line, (int)sizeof(line), f)) {
|
||||||
|
|
@ -666,72 +670,120 @@ static void processHcf(const char *hcfPath, const char *hcfDir) {
|
||||||
if (strncasecmp(line, "output", 6) == 0) {
|
if (strncasecmp(line, "output", 6) == 0) {
|
||||||
const char *p = line + 6;
|
const char *p = line + 6;
|
||||||
|
|
||||||
while (*p == ' ' || *p == '=') {
|
while (*p == ' ' || *p == '=') { p++; }
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(outputFile, sizeof(outputFile), "%s%c%s", hcfDir, DVX_PATH_SEP, p);
|
snprintf(outputFile, sizeof(outputFile), "%s%c%s", hcfDir, DVX_PATH_SEP, p);
|
||||||
|
} else if (strncasecmp(line, "imagedir", 8) == 0) {
|
||||||
|
const char *p = line + 8;
|
||||||
|
|
||||||
|
while (*p == ' ' || *p == '=') { p++; }
|
||||||
|
|
||||||
|
snprintf(imgDir, sizeof(imgDir), "%s", p);
|
||||||
} else if (strncasecmp(line, "source", 6) == 0) {
|
} else if (strncasecmp(line, "source", 6) == 0) {
|
||||||
const char *p = line + 6;
|
const char *p = line + 6;
|
||||||
|
|
||||||
while (*p == ' ' || *p == '=') {
|
while (*p == ' ' || *p == '=') { p++; }
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
char pattern[DVX_MAX_PATH] = {0};
|
char pattern[DVX_MAX_PATH] = {0};
|
||||||
char exclude[DVX_MAX_PATH] = {0};
|
char exclude[DVX_MAX_PATH] = {0};
|
||||||
|
|
||||||
const char *bang = strchr(p, '!');
|
const char *bang = strchr(p, '!');
|
||||||
|
|
||||||
if (bang) {
|
if (bang) {
|
||||||
int32_t patLen = (int32_t)(bang - p);
|
int32_t patLen = (int32_t)(bang - p);
|
||||||
|
|
||||||
while (patLen > 0 && p[patLen - 1] == ' ') {
|
while (patLen > 0 && p[patLen - 1] == ' ') { patLen--; }
|
||||||
patLen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(pattern, p, patLen);
|
memcpy(pattern, p, patLen);
|
||||||
pattern[patLen] = '\0';
|
pattern[patLen] = '\0';
|
||||||
bang++;
|
bang++;
|
||||||
|
|
||||||
while (*bang == ' ') {
|
while (*bang == ' ') { bang++; }
|
||||||
bang++;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(exclude, sizeof(exclude), "%s", bang);
|
snprintf(exclude, sizeof(exclude), "%s", bang);
|
||||||
} else {
|
} else {
|
||||||
snprintf(pattern, sizeof(pattern), "%s", p);
|
snprintf(pattern, sizeof(pattern), "%s", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
long before = ftell(resp);
|
collectGlobFiles(&inputFiles, pattern, exclude[0] ? exclude : NULL);
|
||||||
writeGlobToResp(resp, pattern, exclude[0] ? exclude : NULL);
|
|
||||||
|
|
||||||
if (ftell(resp) > before) {
|
|
||||||
hasFiles = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
fclose(resp);
|
|
||||||
|
|
||||||
if (!outputFile[0] || !hasFiles) {
|
int32_t inputCount = (int32_t)arrlen(inputFiles);
|
||||||
remove(HELP_RESP_FILE);
|
|
||||||
|
if (!outputFile[0] || inputCount == 0) {
|
||||||
|
for (int32_t i = 0; i < inputCount; i++) { free(inputFiles[i]); }
|
||||||
|
arrfree(inputFiles);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short command: compiler + output + response file
|
dvxLog("helpRecompile: %s -> %s (%d files)", hcfPath, outputFile, (int)inputCount);
|
||||||
char cmd[DVX_MAX_PATH * 2];
|
|
||||||
snprintf(cmd, sizeof(cmd), "%s --quiet -o %s @%s", HLPC_PATH, outputFile, HELP_RESP_FILE);
|
|
||||||
|
|
||||||
dvxLog("helpRecompile: %s -> %s", hcfPath, outputFile);
|
int32_t rc = hlpcCompile((const char **)inputFiles, inputCount, outputFile,
|
||||||
int rc = system(cmd);
|
imgDir[0] ? imgDir : NULL, NULL, 1,
|
||||||
|
hlpcProgressCallback, NULL);
|
||||||
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
dvxLog("helpRecompile: FAILED (rc=%d)", rc);
|
dvxLog("helpRecompile: FAILED (rc=%d)", (int)rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(HELP_RESP_FILE);
|
for (int32_t i = 0; i < inputCount; i++) {
|
||||||
|
free(inputFiles[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
arrfree(inputFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Count total progress steps across all .hcf files under a directory.
|
||||||
|
static int32_t countTotalHelpSteps(const char *dirPath) {
|
||||||
|
DIR *dir = opendir(dirPath);
|
||||||
|
|
||||||
|
if (!dir) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char **names = NULL;
|
||||||
|
struct dirent *ent;
|
||||||
|
|
||||||
|
while ((ent = readdir(dir)) != NULL) {
|
||||||
|
if (ent->d_name[0] == '.') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
arrput(names, strdup(ent->d_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
int32_t total = 0;
|
||||||
|
int32_t nEntries = (int32_t)arrlen(names);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < nEntries; i++) {
|
||||||
|
char fullPath[DVX_MAX_PATH];
|
||||||
|
snprintf(fullPath, sizeof(fullPath), "%s%c%s", dirPath, DVX_PATH_SEP, names[i]);
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (stat(fullPath, &st) == 0) {
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
total += countTotalHelpSteps(fullPath);
|
||||||
|
} else {
|
||||||
|
int32_t nameLen = (int32_t)strlen(names[i]);
|
||||||
|
|
||||||
|
if (nameLen > 4 && strcasecmp(names[i] + nameLen - 4, ".hcf") == 0) {
|
||||||
|
int32_t fileCount = countHcfInputFiles(fullPath);
|
||||||
|
total += hlpcProgressTotal(fileCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(names[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
arrfree(names);
|
||||||
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -772,8 +824,6 @@ static void processHcfDir(const char *dirPath) {
|
||||||
|
|
||||||
if (nameLen > 4 && strcasecmp(names[i] + nameLen - 4, ".hcf") == 0) {
|
if (nameLen > 4 && strcasecmp(names[i] + nameLen - 4, ".hcf") == 0) {
|
||||||
processHcf(fullPath, dirPath);
|
processHcf(fullPath, dirPath);
|
||||||
sSplashLoaded++;
|
|
||||||
splashUpdateProgress();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -816,25 +866,11 @@ static void helpRecompileIfNeeded(void) {
|
||||||
dvxLog("helpRecompile: counts changed (libs: %d->%d, widgets: %d->%d)",
|
dvxLog("helpRecompile: counts changed (libs: %d->%d, widgets: %d->%d)",
|
||||||
(int)storedLibs, (int)sLibCount, (int)storedWidgets, (int)sWidgetCount);
|
(int)storedLibs, (int)sLibCount, (int)storedWidgets, (int)sWidgetCount);
|
||||||
|
|
||||||
// Check if compiler exists
|
// Count total progress steps across all .hcf compilations
|
||||||
FILE *test = fopen(HLPC_PATH, "rb");
|
int32_t totalSteps = countTotalHelpSteps("APPS");
|
||||||
|
|
||||||
if (!test) {
|
if (totalSteps == 0) {
|
||||||
dvxLog("helpRecompile: %s not found, skipping", HLPC_PATH);
|
dvxLog("helpRecompile: no help sources found");
|
||||||
prefsSetInt(ini, "help", "libCount", sLibCount);
|
|
||||||
prefsSetInt(ini, "help", "widgetCount", sWidgetCount);
|
|
||||||
prefsSave(ini);
|
|
||||||
prefsClose(ini);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(test);
|
|
||||||
|
|
||||||
// Count .hcf files for progress bar
|
|
||||||
int32_t hcfCount = countHcfFiles();
|
|
||||||
|
|
||||||
if (hcfCount == 0) {
|
|
||||||
dvxLog("helpRecompile: no .hcf files found");
|
|
||||||
prefsSetInt(ini, "help", "libCount", sLibCount);
|
prefsSetInt(ini, "help", "libCount", sLibCount);
|
||||||
prefsSetInt(ini, "help", "widgetCount", sWidgetCount);
|
prefsSetInt(ini, "help", "widgetCount", sWidgetCount);
|
||||||
prefsSave(ini);
|
prefsSave(ini);
|
||||||
|
|
@ -844,7 +880,7 @@ static void helpRecompileIfNeeded(void) {
|
||||||
|
|
||||||
// Reset progress bar for recompile phase
|
// Reset progress bar for recompile phase
|
||||||
sSplashLoaded = 0;
|
sSplashLoaded = 0;
|
||||||
sSplashTotal = hcfCount;
|
sSplashTotal = totalSteps;
|
||||||
platformSplashFillRect(PBAR_X, PBAR_Y, PBAR_W, PBAR_H, SPLASH_BAR_BG);
|
platformSplashFillRect(PBAR_X, PBAR_Y, PBAR_W, PBAR_H, SPLASH_BAR_BG);
|
||||||
|
|
||||||
// Recursively scan APPS/ for .hcf files and process each
|
// Recursively scan APPS/ for .hcf files and process each
|
||||||
|
|
|
||||||
|
|
@ -50,12 +50,19 @@ $(BINDIR):
|
||||||
$(CONFIGDIR):
|
$(CONFIGDIR):
|
||||||
mkdir -p $(CONFIGDIR)
|
mkdir -p $(CONFIGDIR)
|
||||||
|
|
||||||
$(SYSTEMDIR)/DVXHLPC.EXE: dvxhlpc.c ../apps/dvxhelp/hlpformat.h | $(SYSTEMDIR)
|
$(SYSTEMDIR)/DVXHLPC.EXE: dvxhlpc.c hlpcCompile.h ../apps/dvxhelp/hlpformat.h | $(SYSTEMDIR)
|
||||||
$(DOSCC) $(DOSCFLAGS) -o $(SYSTEMDIR)/dvxhlpc.exe dvxhlpc.c
|
$(DOSCC) $(DOSCFLAGS) -o $(SYSTEMDIR)/dvxhlpc.exe dvxhlpc.c
|
||||||
$(EXE2COFF) $(SYSTEMDIR)/dvxhlpc.exe
|
$(EXE2COFF) $(SYSTEMDIR)/dvxhlpc.exe
|
||||||
cat $(CWSDSTUB) $(SYSTEMDIR)/dvxhlpc > $@
|
cat $(CWSDSTUB) $(SYSTEMDIR)/dvxhlpc > $@
|
||||||
rm -f $(SYSTEMDIR)/dvxhlpc $(SYSTEMDIR)/dvxhlpc.exe
|
rm -f $(SYSTEMDIR)/dvxhlpc $(SYSTEMDIR)/dvxhlpc.exe
|
||||||
|
|
||||||
|
# Object file for linking into the loader (no main)
|
||||||
|
../obj/loader/dvxhlpc.o: dvxhlpc.c hlpcCompile.h ../apps/dvxhelp/hlpformat.h | ../obj/loader
|
||||||
|
$(DOSCC) $(DOSCFLAGS) -DHLPC_NO_MAIN -c -o $@ dvxhlpc.c
|
||||||
|
|
||||||
|
../obj/loader:
|
||||||
|
mkdir -p ../obj/loader
|
||||||
|
|
||||||
$(SYSTEMDIR)/DVXRES.EXE: dvxres.c ../core/dvxResource.c ../core/dvxRes.h | $(SYSTEMDIR)
|
$(SYSTEMDIR)/DVXRES.EXE: dvxres.c ../core/dvxResource.c ../core/dvxRes.h | $(SYSTEMDIR)
|
||||||
$(DOSCC) $(DOSCFLAGS) -o $(SYSTEMDIR)/dvxres.exe dvxres.c ../core/dvxResource.c
|
$(DOSCC) $(DOSCFLAGS) -o $(SYSTEMDIR)/dvxres.exe dvxres.c ../core/dvxResource.c
|
||||||
$(EXE2COFF) $(SYSTEMDIR)/dvxres.exe
|
$(EXE2COFF) $(SYSTEMDIR)/dvxres.exe
|
||||||
|
|
@ -67,6 +74,12 @@ $(SYSTEMDIR):
|
||||||
|
|
||||||
deploy-helpsrc:
|
deploy-helpsrc:
|
||||||
@echo "Deploying help source files..."
|
@echo "Deploying help source files..."
|
||||||
|
@# Deploy help images from core/
|
||||||
|
@for f in ../core/*.png; do \
|
||||||
|
[ -f "$$f" ] || continue; \
|
||||||
|
name=$$(basename "$$f" | tr a-z A-Z); \
|
||||||
|
cp "$$f" $(BINDIR)/libs/kpunch/libdvx/"$$name"; \
|
||||||
|
done
|
||||||
@for pair in \
|
@for pair in \
|
||||||
"../core/*.dhs:$(BINDIR)/libs/kpunch/libdvx" \
|
"../core/*.dhs:$(BINDIR)/libs/kpunch/libdvx" \
|
||||||
"../tasks/*.dhs:$(BINDIR)/libs/kpunch/libtasks" \
|
"../tasks/*.dhs:$(BINDIR)/libs/kpunch/libtasks" \
|
||||||
|
|
|
||||||
261
tools/dvxhlpc.c
261
tools/dvxhlpc.c
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include "hlpcCompile.h"
|
||||||
#include "../apps/dvxhelp/hlpformat.h"
|
#include "../apps/dvxhelp/hlpformat.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
@ -135,6 +136,12 @@ static const char *htmlPath = NULL;
|
||||||
static int32_t errorCount = 0;
|
static int32_t errorCount = 0;
|
||||||
static bool quietMode = false;
|
static bool quietMode = false;
|
||||||
|
|
||||||
|
// Progress callback (set by hlpcCompile, NULL for standalone)
|
||||||
|
static HlpcProgressFnT sProgressFn = NULL;
|
||||||
|
static void *sProgressCtx = NULL;
|
||||||
|
static int32_t sProgressCur = 0;
|
||||||
|
static int32_t sProgressTotal = 0;
|
||||||
|
|
||||||
// Parse state
|
// Parse state
|
||||||
static const char *currentFile = NULL;
|
static const char *currentFile = NULL;
|
||||||
static int32_t currentLine = 0;
|
static int32_t currentLine = 0;
|
||||||
|
|
@ -163,7 +170,6 @@ static void freeAll(void);
|
||||||
static void hlpcInfo(const char *fmt, ...);
|
static void hlpcInfo(const char *fmt, ...);
|
||||||
static void parseDirective(const char *line, TopicT **curTopic, bool *inList, bool *inTable, bool *inCode, bool *inNote, uint8_t *noteFlags, char *para, int32_t *paraLen, int32_t includeDepth);
|
static void parseDirective(const char *line, TopicT **curTopic, bool *inList, bool *inTable, bool *inCode, bool *inNote, uint8_t *noteFlags, char *para, int32_t *paraLen, int32_t includeDepth);
|
||||||
static void parseFile(const char *path, TopicT **curTopic, bool *inList, bool *inTable, bool *inCode, bool *inNote, uint8_t *noteFlags, char *para, int32_t *paraLen, int32_t includeDepth);
|
static void parseFile(const char *path, TopicT **curTopic, bool *inList, bool *inTable, bool *inCode, bool *inNote, uint8_t *noteFlags, char *para, int32_t *paraLen, int32_t includeDepth);
|
||||||
static void pass1Parse(int32_t fileCount, char **files);
|
|
||||||
static void pass2Wrap(void);
|
static void pass2Wrap(void);
|
||||||
static void regroupTocBySections(void);
|
static void regroupTocBySections(void);
|
||||||
static void pass3StringTable(void);
|
static void pass3StringTable(void);
|
||||||
|
|
@ -172,7 +178,9 @@ static int pass5Serialize(const char *outputPath);
|
||||||
static int emitHtml(const char *outputPath);
|
static int emitHtml(const char *outputPath);
|
||||||
static int32_t strTableAdd(const char *str);
|
static int32_t strTableAdd(const char *str);
|
||||||
static int32_t strTableFind(const char *str);
|
static int32_t strTableFind(const char *str);
|
||||||
|
#ifndef HLPC_NO_MAIN
|
||||||
static void usage(void);
|
static void usage(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// emitError / emitWarning
|
// emitError / emitWarning
|
||||||
|
|
@ -214,10 +222,12 @@ static void hlpcInfo(const char *fmt, ...) {
|
||||||
// usage
|
// usage
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef HLPC_NO_MAIN
|
||||||
static void usage(void) {
|
static void usage(void) {
|
||||||
fprintf(stderr, "Usage: dvxhlpc -o output.hlp [-i imagedir] [--html out.html] [--quiet] input.dhs [@filelist] [...]\n");
|
fprintf(stderr, "Usage: dvxhlpc -o output.hlp [-i imagedir] [--html out.html] [--quiet] input.dhs [@filelist] [...]\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
@ -850,50 +860,6 @@ static void regroupTocBySections(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void pass1Parse(int32_t fileCount, char **files) {
|
|
||||||
hlpcInfo("Pass 1: Parsing %d input file(s)...\n", fileCount);
|
|
||||||
|
|
||||||
TopicT *curTopic = NULL;
|
|
||||||
bool inList = false;
|
|
||||||
bool inTable = false;
|
|
||||||
bool inCode = false;
|
|
||||||
bool inNote = false;
|
|
||||||
uint8_t noteFlags = 0;
|
|
||||||
|
|
||||||
// Paragraph buffer (shared across files for multi-file topics)
|
|
||||||
char para[MAX_LINE_LEN * 64];
|
|
||||||
int32_t paraLen = 0;
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < fileCount; i++) {
|
|
||||||
currentSection[0] = '\0';
|
|
||||||
parseFile(files[i], &curTopic, &inList, &inTable, &inCode, &inNote, ¬eFlags, para, ¶Len, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush any remaining paragraph
|
|
||||||
if (curTopic && paraLen > 0) {
|
|
||||||
uint8_t type = HLP_REC_TEXT;
|
|
||||||
uint8_t flags = 0;
|
|
||||||
if (inCode) {
|
|
||||||
type = HLP_REC_CODE;
|
|
||||||
} else if (inTable) {
|
|
||||||
type = HLP_REC_TABLE;
|
|
||||||
} else if (inNote) {
|
|
||||||
type = HLP_REC_NOTE;
|
|
||||||
flags = noteFlags;
|
|
||||||
} else if (inList) {
|
|
||||||
type = HLP_REC_LIST_ITEM;
|
|
||||||
}
|
|
||||||
flushParagraph(curTopic, para, paraLen, type, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regroup TOC entries by section
|
|
||||||
regroupTocBySections();
|
|
||||||
|
|
||||||
hlpcInfo(" %d topic(s), %d TOC entries, %d index entries, %d image(s)\n",
|
|
||||||
topicCount, tocCount, indexCount, imageCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Pass 2: Word wrap
|
// Pass 2: Word wrap
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
@ -1475,9 +1441,15 @@ static int emitHtml(const char *outputPath) {
|
||||||
static int pass5Serialize(const char *outputPath) {
|
static int pass5Serialize(const char *outputPath) {
|
||||||
hlpcInfo("Pass 5: Serializing to %s...\n", outputPath);
|
hlpcInfo("Pass 5: Serializing to %s...\n", outputPath);
|
||||||
|
|
||||||
FILE *f = fopen(outputPath, "wb");
|
// Write to a temp file, rename on success. This prevents
|
||||||
|
// truncating the existing help file if compilation fails.
|
||||||
|
char tmpPath[260];
|
||||||
|
snprintf(tmpPath, sizeof(tmpPath), "%s.tmp", outputPath);
|
||||||
|
|
||||||
|
FILE *f = fopen(tmpPath, "wb");
|
||||||
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
fprintf(stderr, "error: cannot create '%s': %s\n", outputPath, strerror(errno));
|
fprintf(stderr, "error: cannot create '%s': %s\n", tmpPath, strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1530,8 +1502,9 @@ static int pass5Serialize(const char *outputPath) {
|
||||||
hdr.imagePoolSize = offset - hdr.imagePoolOffset;
|
hdr.imagePoolSize = offset - hdr.imagePoolOffset;
|
||||||
|
|
||||||
// --- 2. Topic content records ---
|
// --- 2. Topic content records ---
|
||||||
uint32_t *topicContentOffsets = calloc(topicCount, sizeof(uint32_t));
|
int32_t allocCount = topicCount > 0 ? topicCount : 1;
|
||||||
uint32_t *topicContentSizes = calloc(topicCount, sizeof(uint32_t));
|
uint32_t *topicContentOffsets = calloc((size_t)allocCount, sizeof(uint32_t));
|
||||||
|
uint32_t *topicContentSizes = calloc((size_t)allocCount, sizeof(uint32_t));
|
||||||
|
|
||||||
for (int32_t t = 0; t < topicCount; t++) {
|
for (int32_t t = 0; t < topicCount; t++) {
|
||||||
TopicT *topic = &topics[t];
|
TopicT *topic = &topics[t];
|
||||||
|
|
@ -1680,6 +1653,18 @@ static int pass5Serialize(const char *outputPath) {
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
|
// Rename temp file to final output (atomic on same filesystem)
|
||||||
|
remove(outputPath);
|
||||||
|
|
||||||
|
if (rename(tmpPath, outputPath) != 0) {
|
||||||
|
fprintf(stderr, "error: cannot rename '%s' to '%s': %s\n", tmpPath, outputPath, strerror(errno));
|
||||||
|
remove(tmpPath);
|
||||||
|
free(topicDir);
|
||||||
|
free(topicContentOffsets);
|
||||||
|
free(topicContentSizes);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
free(topicDir);
|
free(topicDir);
|
||||||
free(topicContentOffsets);
|
free(topicContentOffsets);
|
||||||
free(topicContentSizes);
|
free(topicContentSizes);
|
||||||
|
|
@ -1708,10 +1693,151 @@ static void freeAll(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void resetAll(void) {
|
||||||
|
topicCount = 0;
|
||||||
|
tocCount = 0;
|
||||||
|
indexCount = 0;
|
||||||
|
imageCount = 0;
|
||||||
|
trigramCount = 0;
|
||||||
|
strTab = NULL;
|
||||||
|
strTabSize = 0;
|
||||||
|
strTabCap = 0;
|
||||||
|
strEntries = NULL;
|
||||||
|
strEntryCount = 0;
|
||||||
|
strEntryCap = 0;
|
||||||
|
errorCount = 0;
|
||||||
|
currentFile = NULL;
|
||||||
|
currentLine = 0;
|
||||||
|
currentSection[0] = '\0';
|
||||||
|
snprintf(imageDir, sizeof(imageDir), ".");
|
||||||
|
htmlPath = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void progressStep(void) {
|
||||||
|
if (sProgressFn) {
|
||||||
|
sProgressCur++;
|
||||||
|
sProgressFn(sProgressCtx, sProgressCur, sProgressTotal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// main
|
// hlpcCompile -- library entry point
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int32_t hlpcCompile(const char **inputFiles, int32_t inputCount, const char *outputPath, const char *imgDir, const char *html, int32_t quiet, HlpcProgressFnT progressFn, void *progressCtx) {
|
||||||
|
resetAll();
|
||||||
|
|
||||||
|
if (imgDir) {
|
||||||
|
snprintf(imageDir, sizeof(imageDir), "%s", imgDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
htmlPath = html;
|
||||||
|
quietMode = quiet ? true : false;
|
||||||
|
|
||||||
|
sProgressFn = progressFn;
|
||||||
|
sProgressCtx = progressCtx;
|
||||||
|
sProgressCur = 0;
|
||||||
|
sProgressTotal = hlpcProgressTotal(inputCount);
|
||||||
|
|
||||||
|
if (progressFn) {
|
||||||
|
progressFn(progressCtx, 0, sProgressTotal);
|
||||||
|
}
|
||||||
|
|
||||||
|
hlpcInfo("dvxhlpc: DVX Help Compiler\n");
|
||||||
|
|
||||||
|
// Pass 1: parse input files (one progress step per file)
|
||||||
|
{
|
||||||
|
TopicT *curTopic = NULL;
|
||||||
|
bool inList = false;
|
||||||
|
bool inTable = false;
|
||||||
|
bool inCode = false;
|
||||||
|
bool inNote = false;
|
||||||
|
uint8_t noteFlags = 0;
|
||||||
|
char para[MAX_LINE_LEN * 64];
|
||||||
|
int32_t paraLen = 0;
|
||||||
|
|
||||||
|
hlpcInfo("Pass 1: Parsing %d input file(s)...\n", inputCount);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < inputCount; i++) {
|
||||||
|
currentSection[0] = '\0';
|
||||||
|
parseFile(inputFiles[i], &curTopic, &inList, &inTable, &inCode, &inNote, ¬eFlags, para, ¶Len, 0);
|
||||||
|
progressStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curTopic && paraLen > 0) {
|
||||||
|
uint8_t type = HLP_REC_TEXT;
|
||||||
|
uint8_t flags = 0;
|
||||||
|
|
||||||
|
if (inCode) {
|
||||||
|
type = HLP_REC_CODE;
|
||||||
|
} else if (inTable) {
|
||||||
|
type = HLP_REC_TABLE;
|
||||||
|
} else if (inNote) {
|
||||||
|
type = HLP_REC_NOTE;
|
||||||
|
flags = noteFlags;
|
||||||
|
} else if (inList) {
|
||||||
|
type = HLP_REC_LIST_ITEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
flushParagraph(curTopic, para, paraLen, type, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
regroupTocBySections();
|
||||||
|
|
||||||
|
hlpcInfo(" %d topic(s), %d TOC entries, %d index entries, %d image(s)\n",
|
||||||
|
topicCount, tocCount, indexCount, imageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorCount > 0) {
|
||||||
|
fprintf(stderr, "Aborting due to %d error(s).\n", (int)errorCount);
|
||||||
|
freeAll();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass 2: word-wrap
|
||||||
|
pass2Wrap();
|
||||||
|
progressStep();
|
||||||
|
|
||||||
|
// HTML output (uses wrapped text, before binary passes)
|
||||||
|
if (htmlPath) {
|
||||||
|
if (emitHtml(htmlPath) == 0) {
|
||||||
|
hlpcInfo("HTML: wrote %s\n", htmlPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass 3: string table
|
||||||
|
pass3StringTable();
|
||||||
|
progressStep();
|
||||||
|
|
||||||
|
// Pass 4: search index
|
||||||
|
pass4SearchIndex();
|
||||||
|
progressStep();
|
||||||
|
|
||||||
|
// Pass 5: serialize
|
||||||
|
int32_t result = pass5Serialize(outputPath);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
hlpcInfo("Done. %d topic(s), %d TOC entries, %d index keywords, %d trigrams.\n",
|
||||||
|
topicCount, tocCount, indexCount, trigramCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
progressStep();
|
||||||
|
freeAll();
|
||||||
|
|
||||||
|
sProgressFn = NULL;
|
||||||
|
sProgressCtx = NULL;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// main -- standalone executable wrapper (excluded when linking as library)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef HLPC_NO_MAIN
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const char *outputPath = NULL;
|
const char *outputPath = NULL;
|
||||||
char *inputFiles[256];
|
char *inputFiles[256];
|
||||||
|
|
@ -1789,33 +1915,14 @@ int main(int argc, char **argv) {
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
hlpcInfo("dvxhlpc: DVX Help Compiler\n");
|
// Copy imageDir and htmlPath before hlpcCompile resets the globals
|
||||||
|
char imgDirCopy[260];
|
||||||
|
snprintf(imgDirCopy, sizeof(imgDirCopy), "%s", imageDir);
|
||||||
|
|
||||||
pass1Parse(inputCount, inputFiles);
|
const char *htmlCopy = htmlPath;
|
||||||
if (errorCount > 0) {
|
|
||||||
fprintf(stderr, "Aborting due to %d error(s).\n", (int)errorCount);
|
|
||||||
freeAll();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pass2Wrap();
|
return hlpcCompile((const char **)inputFiles, inputCount, outputPath,
|
||||||
|
imgDirCopy[0] ? imgDirCopy : NULL,
|
||||||
// Emit HTML if requested (uses wrapped text, before binary passes)
|
htmlCopy, quietMode, NULL, NULL);
|
||||||
if (htmlPath) {
|
|
||||||
if (emitHtml(htmlPath) == 0) {
|
|
||||||
hlpcInfo("HTML: wrote %s\n", htmlPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pass3StringTable();
|
|
||||||
pass4SearchIndex();
|
|
||||||
|
|
||||||
int result = pass5Serialize(outputPath);
|
|
||||||
if (result == 0) {
|
|
||||||
hlpcInfo("Done. %d topic(s), %d TOC entries, %d index keywords, %d trigrams.\n",
|
|
||||||
topicCount, tocCount, indexCount, trigramCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
freeAll();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
#endif // HLPC_NO_MAIN
|
||||||
|
|
|
||||||
38
tools/hlpcCompile.h
Normal file
38
tools/hlpcCompile.h
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
// hlpcCompile.h -- DVX Help Compiler library interface
|
||||||
|
//
|
||||||
|
// Allows the help compiler to be called as a function (from the
|
||||||
|
// loader for startup recompilation) or as a standalone executable.
|
||||||
|
// The progress callback enables real-time progress bar updates.
|
||||||
|
|
||||||
|
#ifndef HLPC_COMPILE_H
|
||||||
|
#define HLPC_COMPILE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// Progress callback: called after each input file in pass 1 and
|
||||||
|
// after each of passes 2-5. total is set on the first call and
|
||||||
|
// stays constant. current increments from 0 to total.
|
||||||
|
typedef void (*HlpcProgressFnT)(void *ctx, int32_t current, int32_t total);
|
||||||
|
|
||||||
|
// Compile help source files into a binary .hlp file.
|
||||||
|
//
|
||||||
|
// inputFiles: array of .dhs source file paths
|
||||||
|
// inputCount: number of input files
|
||||||
|
// outputPath: path to write the .hlp file
|
||||||
|
// imageDir: directory to search for .image references (NULL = ".")
|
||||||
|
// htmlPath: if non-NULL, also emit HTML to this path
|
||||||
|
// quiet: suppress informational output
|
||||||
|
// progressFn: progress callback (NULL = no progress reporting)
|
||||||
|
// progressCtx: opaque context passed to progressFn
|
||||||
|
//
|
||||||
|
// Returns 0 on success, non-zero on error.
|
||||||
|
int32_t hlpcCompile(const char **inputFiles, int32_t inputCount, const char *outputPath, const char *imageDir, const char *htmlPath, int32_t quiet, HlpcProgressFnT progressFn, void *progressCtx);
|
||||||
|
|
||||||
|
// Return the number of progress steps for a given input count.
|
||||||
|
// This is inputCount (one per file in pass 1) + 4 (passes 2-5).
|
||||||
|
// Useful for pre-computing the total across multiple compilations.
|
||||||
|
static inline int32_t hlpcProgressTotal(int32_t inputCount) {
|
||||||
|
return inputCount + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HLPC_COMPILE_H
|
||||||
Loading…
Add table
Reference in a new issue