mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-22 10:31:47 +00:00
Too much to list all, but includes (in no particular order): - Cleanup for 64-bit builds, MSVC warnings. - Structured help - Help file compiler. - Supports volsets, writes/create work. - Support for I18n in messages, help. - Makefiles. - Initialize volume/volset - Command line editing/history Builds and works on Linux and Windows (VS). Not recently built or tested on other platforms, but not intentinonally broken.
650 lines
20 KiB
C
650 lines
20 KiB
C
/* Copyright (c) Timothe Litt <litt@acm.org>
|
|
*/
|
|
|
|
/* Help file compiler
|
|
*/
|
|
|
|
/* This is part of ODS2 written by Paul Nankervis,
|
|
* email address: Paulnank@au1.ibm.com
|
|
|
|
* ODS2 is distributed freely for all members of the
|
|
* VMS community to use. However all derived works
|
|
* must maintain comments in their source to acknowledge
|
|
* the contributions of the original author and
|
|
* subsequent contributors. This is free software; no
|
|
* warranty is offered, and while we believe it to be useful,
|
|
* you use it at your own risk.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "compat.h"
|
|
|
|
#define HELPFILEDEFS
|
|
#include "cmddef.h"
|
|
|
|
#define INEXT ".hlp"
|
|
#define OUTEXT ".hlb"
|
|
#define LSTEXT ".lst"
|
|
|
|
#ifdef _WIN64
|
|
#define OUTPFX "win64-ods2_"
|
|
#define DDLIM '\\'
|
|
#elif defined( _WIN32 )
|
|
#define OUTPFX "win-ods2_"
|
|
#define DDLIM '\\'
|
|
#elif defined( VMS )
|
|
#define OUTPFX "ods2_"
|
|
#define DDLIM ']'
|
|
#else
|
|
#define OUTPFX "ods2_"
|
|
#define DDLIM '/'
|
|
#endif
|
|
|
|
/* Leaks are not an issue since this program exits after every command.
|
|
* However, the leak detector is handy for debugging other issues.
|
|
*/
|
|
#if defined( _WIN32 ) && defined(_MSC_VER) && defined( DEBUG_BUILD ) && defined( USE_VLD )
|
|
/* Normally done in the project file, but VLD is optional and I'd rather not provide
|
|
* instructions as they vary by IDE version. See http://vld.codeplex.com/ if interested.
|
|
*/
|
|
#include "C:\\Program Files (x86)\\Visual Leak Detector\\include\\vld.h"
|
|
#pragma comment (lib,"C:\\Program Files (x86)\\Visual Leak Detector\\lib\\Win32\\vld.lib")
|
|
#endif
|
|
|
|
typedef struct hlpstat {
|
|
size_t topics[9];
|
|
size_t keymem[9];
|
|
size_t txtmem[9];
|
|
size_t ntopics;
|
|
size_t keymemtot;
|
|
size_t txtmemtot;
|
|
} hlpstat_t;
|
|
|
|
static void pstats( FILE *of, char *outname, hlpstat_t *stats, size_t memsize );
|
|
static size_t hlpsize( hlproot_t *root );
|
|
static int rdhelp( hlproot_t *root, const char *filename );
|
|
static void helpsort( hlproot_t *root );
|
|
static int hlpcmp( const void *qa, const void *qb );
|
|
static void savehlp( hlproot_t *oroot, hlproot_t *iroot,
|
|
char *base, char **sp, char **pp,
|
|
unsigned lvl, hlpstat_t *stats );
|
|
static int printdata( FILE *of, unsigned level, hlproot_t *root,
|
|
int text, hlpstat_t *stats );
|
|
|
|
/* ******************************************************************* main() */
|
|
|
|
int main( int argc, char **argv ) {
|
|
int opth = 0, optd = 0, optD = 0, optq = 0;
|
|
char *inname = NULL, *outname = NULL, *pname;
|
|
int outmalloced = FALSE;
|
|
size_t memsize = 0;
|
|
hlproot_t inroot;
|
|
hlphdr_t *hdr;
|
|
hlpstat_t stats;
|
|
struct stat instat;
|
|
char *base, *pp, *sp;
|
|
FILE *of = NULL;
|
|
|
|
memset( &inroot, 0, sizeof( inroot ) );
|
|
inroot.topics.ptr = NULL;
|
|
inroot.ntopics = 0;
|
|
|
|
pname = argv[0];
|
|
if( argc <= 1 ) opth = TRUE;
|
|
for( ; argc > 1; --argc, ++argv ) {
|
|
if( !strcmp( argv[1], "--" ) ) break;
|
|
if( *argv[1] == '-' && argv[1][1] ) {
|
|
char *p;
|
|
|
|
for( p = argv[1]+1; *p; p++ ) {
|
|
switch( *p ) {
|
|
case 'h':
|
|
opth = TRUE;
|
|
break;
|
|
case 'd':
|
|
optd = TRUE;
|
|
break;
|
|
case 'D':
|
|
optD = TRUE;
|
|
break;
|
|
case 'q':
|
|
optq = TRUE;
|
|
break;
|
|
default:
|
|
fprintf( stderr, "Unknown option %c\n", argv[1][1] );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if( opth ) {
|
|
printf( "%s [opts] [in" INEXT " [out" OUTEXT "]]\n"
|
|
" -h This help\n"
|
|
" -d Dump structure of input\n"
|
|
" -D Dump structure of input with topic text\n"
|
|
" -q Suppress statistics report\n"
|
|
" -- End of options\n"
|
|
" - is stdin/out\n"
|
|
"If an output file is not specified, the input filename\n"
|
|
"prefixed by " OUTPFX " is used. " OUTEXT " replaces the "
|
|
"input name's extension.\n"
|
|
"With -d or -D, " LSTEXT " replaces the input name's extension.\n"
|
|
"The " OUTEXT " files are architecture-dependent.\n"
|
|
"Under Windows, the default output file is prefixed\n"
|
|
"with 'win-' or 'win64-'.\n", pname? pname : "makehelp" );
|
|
exit( EXIT_SUCCESS );
|
|
}
|
|
if( argc > 1 ) {
|
|
if( strcmp( argv[1], "-" ) ) {
|
|
inname = argv[1];
|
|
}
|
|
--argc; ++argv;
|
|
}
|
|
if( argc > 1 ) {
|
|
if( strcmp( argv[1], "-" ) ) {
|
|
outname = argv[1];
|
|
}
|
|
--argc; ++argv;
|
|
} else {
|
|
if( inname != NULL ) {
|
|
char *p, *outext;
|
|
size_t inlen, extsiz, addlen;
|
|
ptrdiff_t plen = 0;
|
|
|
|
inlen = strlen( inname );
|
|
outext = ( optd || optD )? LSTEXT : OUTEXT;
|
|
addlen =
|
|
extsiz = strlen( outext ) +1;
|
|
#ifdef OUTPFX
|
|
addlen += sizeof( OUTPFX ) -1;
|
|
#endif
|
|
outname = malloc( inlen + addlen );
|
|
if( outname == NULL ) {
|
|
perror( "malloc" );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
outmalloced = TRUE;
|
|
#ifdef OUTPFX
|
|
if( (p = strrchr( inname, DDLIM )) != NULL ) {
|
|
plen = (p - inname) +1;
|
|
p = outname + plen;
|
|
memcpy( outname, inname, plen );
|
|
} else
|
|
p = outname;
|
|
memcpy( p, OUTPFX, sizeof( OUTPFX ) -1 );
|
|
memcpy( p + sizeof( OUTPFX ) -1,
|
|
inname + plen, strlen( inname + plen ) +1 );
|
|
#else
|
|
memcpy( outname, inname + plen, inlen +1 ); /* plen == 0, ensures it's used */
|
|
#endif
|
|
if( (p = strrchr( outname, '.' )) != NULL && strchr( p, DDLIM ) == NULL ) {
|
|
*p = '\0';
|
|
}
|
|
memcpy( outname + strlen(outname), outext, extsiz );
|
|
}
|
|
}
|
|
if( argc >1 ) {
|
|
fprintf( stderr, "Too many command arguments\n" );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
|
|
if( optd || optD ) {
|
|
if( outname == NULL )
|
|
of = stdout;
|
|
else {
|
|
of = openf( outname, "w" );
|
|
if( !of ) {
|
|
perror( outname );
|
|
if( outmalloced) free( outname );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
}
|
|
}
|
|
memset( &stats, 0, sizeof( stats ) );
|
|
memset( &instat, 0, sizeof( instat ) );
|
|
if( inname == NULL || stat( inname, &instat ) != 0 )
|
|
instat.st_mtime = 0;
|
|
|
|
if( !optq ) {
|
|
time_t now;
|
|
FILE *pf;
|
|
char *rpi = NULL;
|
|
|
|
if( inname != NULL )
|
|
rpi = get_realpath( inname );
|
|
pf = (optd || optD)? of : stderr;
|
|
fprintf( pf, "Topic structure of %s\n",
|
|
inname? (rpi? rpi : inname) : "<stdin>" );
|
|
if( rpi ) free( rpi );
|
|
if( instat.st_mtime != 0 ) {
|
|
char *mt;
|
|
mt = Ctime( &instat.st_mtime );
|
|
if( mt != NULL ) {
|
|
now = time( &now );
|
|
fprintf( pf, "File: %s ", mt );
|
|
free( mt );
|
|
mt = Ctime( &now );
|
|
if( mt != NULL ) {
|
|
fprintf( pf, "as of %s", mt );
|
|
free( mt );
|
|
}
|
|
fprintf( pf, "\n" );
|
|
}
|
|
}
|
|
fprintf( pf,
|
|
"---------------------------------------------------------------\n" );
|
|
}
|
|
|
|
if( rdhelp( &inroot, inname ) ) {
|
|
if( outmalloced) free( outname );
|
|
perror( inname );
|
|
if( of && of != stdout && of != stderr ) fclose( of );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
memsize = sizeof( inroot) + hlpsize( &inroot );
|
|
|
|
if( optd || optD ) {
|
|
printdata( of, 1, &inroot, optD, &stats );
|
|
if( !optq ) pstats( of, outname, &stats, memsize );
|
|
if( of && of != stdout && of != stderr ) fclose( of );
|
|
if( outmalloced) free( outname );
|
|
exit( EXIT_SUCCESS );
|
|
}
|
|
|
|
base = malloc( sizeof( hlphdr_t ) + memsize );
|
|
if( !base ) {
|
|
perror("malloc");
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
hdr = (hlphdr_t *)base;
|
|
sp = base + sizeof( hlphdr_t );
|
|
pp = sp + memsize;
|
|
|
|
memset( hdr, 0, sizeof( *hdr ) );
|
|
memcpy( hdr->magic, HLP_MAGIC, sizeof( HLP_MAGIC ) );
|
|
hdr->version = HLP_VERSION;
|
|
hdr->psize = sizeof( void * );
|
|
hdr->ssize = sizeof( size_t );
|
|
hdr->tsize = sizeof( time_t );
|
|
hdr->ddate = instat.st_mtime;
|
|
hdr->size = memsize;
|
|
|
|
savehlp( NULL, &inroot, base, &sp, &pp, 1, &stats );
|
|
|
|
if( outname == NULL )
|
|
of = stdout;
|
|
else {
|
|
of = openf( outname, "wb" );
|
|
if( !of ) {
|
|
perror( outname );
|
|
if( outmalloced) free( outname );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
}
|
|
if( !optq) pstats( stderr, outname, &stats, memsize );
|
|
fwrite( base, 1, memsize + sizeof( hlphdr_t ), of );
|
|
if( of && of != stdout && of != stderr ) fclose( of );
|
|
free( base );
|
|
if( outmalloced) free( outname );
|
|
exit( EXIT_SUCCESS );
|
|
}
|
|
|
|
/* ***************************************************************** pstats() */
|
|
static void pstats( FILE *of, char *outname, hlpstat_t *stats, size_t memsize ) {
|
|
size_t i;
|
|
char *p = NULL;
|
|
|
|
if( outname != NULL && (p = get_realpath( outname )) != NULL )
|
|
outname = p;
|
|
fprintf( of,
|
|
"\n---------------------------------------------------------------\n"
|
|
"Summary of: %s\n", outname == NULL? "<stdout>" : outname );
|
|
if( p != NULL ) free( p );
|
|
for( i = 0; i < 9; i++ ) {
|
|
if( stats->topics[i] ) {
|
|
fprintf( of,
|
|
"Level %u topics: %4u Key memory: %5u bytes Text memory: %5u\n",
|
|
(unsigned)i+1, (unsigned)stats->topics[i],
|
|
(unsigned)stats->keymem[i],
|
|
(unsigned)stats->txtmem[i] );
|
|
stats->ntopics++;
|
|
stats->keymemtot += stats->keymem[i];
|
|
stats->txtmemtot += stats->txtmem[i];
|
|
}
|
|
}
|
|
fprintf( of, " Total topics: %4u Key memory: %5u bytes Text memory: %5u\n",
|
|
(unsigned)stats->ntopics, (unsigned)stats->keymemtot,
|
|
(unsigned)stats->txtmemtot );
|
|
fprintf( of, " Index memory: %5u bytes Data memory: %5u\n",
|
|
(unsigned)(memsize - (stats->keymemtot + stats->txtmemtot)),
|
|
(unsigned)(stats->keymemtot + stats->txtmemtot));
|
|
return;
|
|
}
|
|
|
|
/* **************************************************************** hlpsize() */
|
|
|
|
static size_t hlpsize( hlproot_t *root ) {
|
|
hlptopic_t *hlp;
|
|
size_t size = 0;
|
|
|
|
if( root->ntopics == 0 ) {
|
|
fprintf( stderr, "Encountered an empty root\n" );
|
|
return size;
|
|
}
|
|
for( hlp = root->topics.ptr;
|
|
hlp < (hlptopic_t *)root->topics.ptr + root->ntopics; hlp++ ) {
|
|
size += strlen( hlp->key.ptr ) +1;
|
|
size += strlen( hlp->text.ptr ) +1;
|
|
if( hlp->subtopics.ntopics )
|
|
size += hlpsize( &hlp->subtopics );
|
|
}
|
|
size += root->ntopics * sizeof( hlptopic_t );
|
|
return size;
|
|
}
|
|
|
|
/*************************************************************** rdhelp() */
|
|
static
|
|
int rdhelp( hlproot_t *toproot, const char *filename ) {
|
|
FILE *fp;
|
|
size_t bufsize = 80;
|
|
char *buf = NULL, *rec;
|
|
hlproot_t *root = NULL;
|
|
hlptopic_t *hlp = NULL,
|
|
*tpath[9];
|
|
unsigned int level = 0, n, lineno = 0;
|
|
|
|
if( filename == NULL )
|
|
fp = stdin;
|
|
else {
|
|
if( (fp = openf( filename, "r" )) == NULL )
|
|
return errno;
|
|
}
|
|
memset( tpath, 0, sizeof( tpath ) );
|
|
|
|
for( rec = NULL; ; ) {
|
|
char *p, *t;
|
|
size_t txtlen = 0, len;
|
|
|
|
/* Read initial search key */
|
|
if( rec == NULL ) {
|
|
++lineno;
|
|
if( (rec = fgetline( fp, FALSE, &buf, &bufsize )) == NULL )
|
|
break; /* EOF */
|
|
}
|
|
if( (p = strchr( rec, '\r' )) != NULL ) {
|
|
*p = '\0';
|
|
}
|
|
p = rec + 2;
|
|
if( rec[0] == '!' ||
|
|
!(strlen(rec) >= 3 &&
|
|
rec[0] >= '1' && rec[0] <= '9' &&
|
|
rec[1] == ' ' && isprint( p[ (len = strspn( p, " " )) ]) ) ) {
|
|
rec = NULL;
|
|
continue; /* Comment or not a search key record */
|
|
}
|
|
p += len; /* Search key starts after level + 1 or more spaces */
|
|
|
|
/* Start new topic */
|
|
|
|
n = rec[0] - '1';
|
|
if( n <= level ) {
|
|
if( n )
|
|
root = &tpath[n-1]->subtopics;
|
|
else
|
|
root = toproot;
|
|
} else if( n != level +1 ) {
|
|
free( buf );
|
|
if( filename != NULL) fclose( fp );
|
|
fprintf( stderr, "Level error at line %u\n", lineno );
|
|
exit( EXIT_FAILURE );
|
|
} else { /* hlp can't be NULL, for code analyzer */
|
|
if( hlp ) root = &hlp->subtopics;
|
|
}
|
|
level = n;
|
|
|
|
if( !root ) exit(EXIT_FAILURE); /* More code analyzer */
|
|
if( (hlp = realloc( root->topics.ptr,
|
|
(root->ntopics + 1) * sizeof( hlptopic_t ) )) == NULL ) {
|
|
free( buf );
|
|
if( filename != NULL) fclose( fp );
|
|
return errno;
|
|
}
|
|
root->topics.ptr = hlp;
|
|
hlp += root->ntopics++;
|
|
tpath[level] = hlp;
|
|
len = strlen( p ) + 1;
|
|
if( (hlp->key.ptr = malloc( len )) == NULL ) {
|
|
free( buf );
|
|
if( filename != NULL) fclose( fp );
|
|
return errno;
|
|
}
|
|
memcpy( hlp->key.ptr, p, len );
|
|
hlp->keylen = (uint32_t)(len -1);
|
|
hlp->text.ptr = NULL;
|
|
hlp->subtopics.topics.ptr = NULL;
|
|
hlp->subtopics.ntopics = 0;
|
|
|
|
/* Add text */
|
|
|
|
while( (rec = fgetline( fp, TRUE, &buf, &bufsize )) != NULL ) {
|
|
++lineno;
|
|
if( (p = strchr( rec, '\r' )) != NULL ) {
|
|
*p++ = '\n';
|
|
*p = '\0';
|
|
}
|
|
if( rec[0] == '!' ) { /* Comment */
|
|
continue;
|
|
}
|
|
p = rec;
|
|
if( strlen(p) >= 3 &&
|
|
(rec[0] >= '1' && rec[0] <= '9') &&
|
|
rec[1] == ' ' && isprint( p[ strspn( p + 2, " " ) ] ) ) {
|
|
if( (p = strchr( p, '\n' )) )
|
|
*p = '\0';
|
|
break; /* New search key, rescan this record */
|
|
}
|
|
|
|
len = strlen( p );
|
|
if( len >= 2 && p[len-2] == '$' && p[len-1] == '\n' ) {
|
|
p[len-2] = '\0'; /* Strip \n for lines ending in $ */
|
|
--len;
|
|
}
|
|
++len;
|
|
if( hlp->text.ptr ) {
|
|
if(txtlen != strlen(hlp->text.ptr)) printf( "len mismatch\n");
|
|
} else if( txtlen ) printf( "Missing text\n");
|
|
if( (t = realloc( hlp->text.ptr, txtlen + len)) == NULL ) {
|
|
free( buf );
|
|
if( filename != NULL) fclose( fp );
|
|
return errno;
|
|
}
|
|
hlp->text.ptr = t;
|
|
memcpy( (char *)hlp->text.ptr + txtlen, p, len );
|
|
txtlen += --len;
|
|
rec = NULL;
|
|
} /* Add topic text */
|
|
if( hlp->text.ptr == NULL ) {
|
|
fprintf( stderr, "No text for %s at line %u\n",
|
|
(char *)hlp->key.ptr, lineno );
|
|
free( rec );
|
|
if( filename != NULL) fclose( fp );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
} /* Add topic */
|
|
free( buf );
|
|
if( filename != NULL) fclose( fp );
|
|
if( toproot->ntopics == 0 ) {
|
|
fprintf( stderr, "No topics found at line %u\n", lineno );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
helpsort( toproot );
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************** helpsort() */
|
|
|
|
static void helpsort( hlproot_t *root ) {
|
|
hlptopic_t *hlp;
|
|
|
|
if( root->topics.ptr == NULL ) {
|
|
fprintf( stderr, "Node has no topics\n" );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
|
|
for( hlp = root->topics.ptr;
|
|
hlp < (hlptopic_t *)root->topics.ptr + root->ntopics; hlp++ ) {
|
|
if( hlp->text.ptr == NULL ) {
|
|
fprintf( stderr, "No text for %s\n", (char *)hlp->key.ptr );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
if( hlp->subtopics.topics.ptr )
|
|
helpsort( &hlp->subtopics );
|
|
}
|
|
|
|
qsort( root->topics.ptr, root->ntopics, sizeof( hlptopic_t ), &hlpcmp );
|
|
|
|
return;
|
|
}
|
|
|
|
/***************************************************************** hlpcmp() */
|
|
|
|
static int hlpcmp( const void *ta, const void *tb ) {
|
|
const char *a, *b;
|
|
size_t alen, blen;
|
|
|
|
a = ((hlptopic_t *)ta)->key.ptr;
|
|
b = ((hlptopic_t *)tb)->key.ptr;
|
|
alen = ((hlptopic_t *)ta)->keylen;
|
|
blen = ((hlptopic_t *)tb)->keylen;
|
|
|
|
while( alen && blen ) {
|
|
int c;
|
|
|
|
c = tolower( (unsigned char)*a ) - tolower( (unsigned char)*b );
|
|
if( c != 0 )
|
|
return c;
|
|
++a; ++b; --alen; --blen;
|
|
}
|
|
|
|
return (int)(alen - blen);
|
|
}
|
|
|
|
/* **************************************************************** savehlp() */
|
|
|
|
static void savehlp( hlproot_t *oroot, hlproot_t *iroot,
|
|
char *base,char **sp, char **pp,
|
|
unsigned lvl, hlpstat_t *stats ) {
|
|
size_t t;
|
|
hlptopic_t *ihlp, *ohlp;
|
|
hlproot_t *rp;
|
|
|
|
/* sp allocates structures toward increasing addresses.
|
|
* pp allocates strings toward decreasing addresses.
|
|
* This ensures that alignment is accounted for.
|
|
* All pointers in the input tree are offsets in the output.
|
|
*/
|
|
if( oroot == NULL ) { /* Top root */
|
|
rp = (hlproot_t *)*sp;
|
|
*sp = (char *)(rp + 1);
|
|
memset( rp, 0, sizeof( *rp ) );
|
|
} else
|
|
rp = oroot; /* Subtopic root */
|
|
|
|
ohlp = (hlptopic_t *)*sp; /* Topic list for this root */
|
|
rp->topics.ofs = (char *)ohlp - base;
|
|
t =
|
|
rp->ntopics = iroot->ntopics;
|
|
t *= sizeof( hlptopic_t );
|
|
*sp += t;
|
|
memset( ohlp, 0, t );
|
|
|
|
for( ihlp = iroot->topics.ptr, t = 0; t < iroot->ntopics; ihlp++, t++ ) {
|
|
size_t len;
|
|
|
|
stats->topics[lvl-1]++;
|
|
|
|
memset( ohlp, 0, sizeof( *ohlp ) );
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning (disable: 6001)
|
|
#endif
|
|
/* N.B. Pointers ARE initialized */
|
|
len = strlen( ihlp->key.ptr ) +1;
|
|
stats->keymem[lvl-1] += len;
|
|
*pp = (char *)*pp - len;
|
|
memcpy( *pp, ihlp->key.ptr, len );
|
|
free( (void *)ihlp->key.ptr );
|
|
ohlp->key.ofs = *pp - base;
|
|
ohlp->keylen = (uint32_t)len -1;
|
|
|
|
len = strlen( ihlp->text.ptr ) +1;
|
|
stats->txtmem[lvl-1] += len;
|
|
*pp = (char *)*pp - len;
|
|
memcpy( *pp, ihlp->text.ptr, len );
|
|
free( (void *)ihlp->text.ptr );
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
ohlp->text.ofs = *pp - base;
|
|
|
|
ohlp->subtopics.ntopics = ihlp->subtopics.ntopics;
|
|
if( ihlp->subtopics.ntopics ) {
|
|
ohlp->subtopics.topics.ofs = *sp - base;
|
|
savehlp( &ohlp->subtopics, &ihlp->subtopics, base, sp, pp,
|
|
lvl+1, stats );
|
|
} else {
|
|
ohlp->subtopics.topics.ofs = 0;
|
|
}
|
|
++ohlp;
|
|
}
|
|
free( (void *)iroot->topics.ptr );
|
|
return;
|
|
}
|
|
|
|
/*************************************************************** printdata() */
|
|
|
|
static int printdata( FILE *of, unsigned level, hlproot_t *root,
|
|
int text, hlpstat_t *stats ) {
|
|
int sts;
|
|
hlptopic_t *hlp;
|
|
|
|
if( root->topics.ptr == NULL )
|
|
return 1;
|
|
|
|
for( hlp = root->topics.ptr;
|
|
hlp < (hlptopic_t *)root->topics.ptr + root->ntopics; hlp++ ) {
|
|
stats->topics[level-1]++;
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning (disable: 6001)
|
|
#endif
|
|
/* N.B. Pointers ARE initialized */
|
|
fprintf( of, "%*s %u %s\n", level, "", level, (char *)hlp->key.ptr );
|
|
free( hlp->key.ptr );
|
|
if( hlp->text.ptr == NULL )
|
|
return 0;
|
|
stats->keymem[level-1] += (size_t)hlp->keylen+1;
|
|
stats->txtmem[level-1] += strlen( (char *)hlp->text.ptr ) +1;
|
|
if( text )
|
|
printf( "%s\n", (char *)hlp->text.ptr );
|
|
free( hlp->text.ptr );
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
if( hlp->subtopics.topics.ptr != NULL &&
|
|
!(sts = printdata( of, level +1, &hlp->subtopics, text, stats )) )
|
|
return sts;
|
|
}
|
|
free( root->topics.ptr );
|
|
root->topics.ptr = NULL;
|
|
root->ntopics = 0;
|
|
return 1;
|
|
}
|