| home | contents | previous | next page | send comment | send link | add bookmark |

makehelp.cpp

/*-------------------------------------------------------------------------*
    MAKEHELP.CPP

    creates a data file from a text file for use by the
    on-line help module 'timehelp'

    a topic must begin with a line:         #<topic name>$

    the last line of source text must be:   #INDEX$

    by:  Stephen R. Schmitt
 *-------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node
{
    node *left;                                 // ptr to left node
    node *right;                                // ptr to right node
    char *name;                                 // ptr to topic string
    long offset;                                // file offset of topic
}
NODE;

NODE *Topic_table = NULL;

NODE Topic_list[1024];

int Topic = 0;

/*-------------------------------------------------------------------------*
 *  "lookup" searches for an identifier in the symbol table.
 *  A pointer is returned if the identifier is found; NULL if not.
 *
 *  returns:  a pointer to the symbol table entry or NULL
 */
NODE *lookup( char *name,                       // of topic
              NODE *idp )                       // of symbol table
{
    int cmp;

    while( idp != NULL )                        // another branch?
    {
        cmp = strcmp( name, idp->name );
        if( cmp == 0 ) 
            return( idp );                      // found match

        if( cmp < 0 ) 
            idp = idp->left;
        else 
            idp = idp->right;
   }

   return( NULL );                              // if name not found
}

/*-------------------------------------------------------------------------*
 *  "insert" puts a new name into the symbol table.
 *
 *  WARNING:  Before using this function, "lookup" must return NULL.
 *
 *  returns:  a pointer to the symbol table entry
 */
NODE *insert( char *name,                       // of topic
              NODE **idpp )                     // of symbol table
{
   int cmp;
   NODE *new_idp, *idp;

   /*
    * create a new node for the identifier
    */
   new_idp = (NODE *)calloc( 1, sizeof( NODE ) );
   if( new_idp == NULL )
   {
       printf( "Error: OUT OF MEMORY\n" );
       exit( 0 );
   }

   /*
    * initialize
    */
   new_idp->left = NULL;
   new_idp->right = NULL;
   new_idp->name = (char *)calloc( 1, strlen( name ) + 1 );
   strcpy( new_idp->name, name );

   idp = *idpp;                              // initial node pointer

   /*
    * now search for insertion point
    */
   while( idp != NULL )
   {
      cmp = strcmp( name, idp->name );

      if( cmp < 0 )
         idpp = &(idp->left);
      else
         idpp = &(idp->right);

      idp = *idpp;
   }

   /*
    * set left/right pointer to new_idp
    */
   *idpp = new_idp;

   return( new_idp );
}

/*-------------------------------------------------------------------------*
 *  "create_topic_table" reads a text file and builds a linked list of
 *  topic titles.
 *
 *  returns:  length of text file
 */
long create_topic_table( FILE *txt )            // source file
{
    int i, line, target;
    long offset;
    NODE *idp;                                  // for node creation
    char buffer[80];

    offset = 0;
    line = 0;

    while( fgets( buffer, 80, txt )  )
    {
        line++;
        offset += strlen( buffer ) + 1;
        target = 0;

        if( buffer[0] == '#' )
        {
            for( i = 0; i < 80; i++ )
            {
                if( buffer[i+1] == '$' )
                {
                    buffer[i] = 0;
                    target = 1;
                    break;
                }
                else
                    buffer[i] = buffer[i+1];
            }

            if( !target )
                printf( "-#- without matching -$- line %d\n", line );
            else
            {
                printf( "topic -%s- offset %d\n", 
                         buffer, offset );

                idp = lookup( buffer, Topic_table );
                if( idp == NULL )
                {
                    idp = insert( buffer, &Topic_table );
                    idp->offset = offset;
                }
                else
                     printf( "duplicate topic -%s- line %d\n", 
                             buffer, line );

                // stop when end of source is reached
                if( !strcmp( "INDEX", buffer ) )
                     break;
            }
        }
    }
    return( offset );
}

/*-------------------------------------------------------------------------*
 *  "verify_jumps" re-reads a text file and checks that a topic exists
 *  for each jump.
 *
 *  returns:  nothing
 */
void verify_jumps( FILE *txt )                  // source file
{
    int  line, jump;
    char *p, *beg, *end;
    NODE *idp;                                  // for node creation
    char topic[80];
    char buffer[80];

    rewind( txt );
    line = 0;
    
    while( fgets( buffer, 80, txt )  )
    {
        line++;
        jump = 0;
        p = buffer;

        while( *p && *p != '\n' )
        {
            if( *p == '@' )
            {
                p++;
                beg = p;
                jump = 1;
            }
            else if( *p == '$' )
            {
                if( jump )
                {
                    end = p;
                    memset( topic, 0, 32 );
                    strncpy( topic, beg, (int)(end - beg) );
                    idp = lookup( topic, Topic_table );
                    if( !idp )
                        printf( "jump to non-existant topic -%s- line %d\n",
                                topic, line );
                }
                p++;
                jump = 0;
            }

            p++;
        }

        if( jump )
            printf( "-@- without matching -$- line %d\n", line );
    }
}

/*-------------------------------------------------------------------------*
 *  "traverse" steps through the doubly linked list and creates a topic
 *  list in alphabetical order.
 *
 *  returns:  nothing
 */
void traverse( NODE *idp )
{
    if( idp )
    {
        traverse( idp->left );

        Topic_list[Topic] = *idp;
        Topic++;

        traverse( idp->right );
    }
}

/*-------------------------------------------------------------------------*
 *  "make_jump_table" generates a jump table which consists of topic names 
 *  and file offset values to be used in the help application to locate
 *  topics.
 *
 *  returns:  nothing
 */
void make_jump_table( FILE *hlp,                // output file
                      long len )                // of input file
{
    int i;

    for( i = 0; i < Topic; i++ )
    {
        if( strcmp( "INDEX", Topic_list[i].name ) )
        {
            fprintf( hlp, 
                     "<%s>%ld\n", 
                     Topic_list[i].name, 
                     Topic_list[i].offset );
        }
    }
    fprintf( hlp, "<>%ld\n", len );             // jump to index
}

/*-------------------------------------------------------------------------*
 *  "append_topic_text" copies a text file to the help data file
 *
 *  returns:  nothing
 */
void append_topic_text( FILE *hlp,              // help data file
                        FILE *txt )             // source text file
{
    char buffer[80];

    rewind( txt );

    while( fgets( buffer, 80, txt )  )
    {
        if( !strncmp( "#INDEX$", buffer, 7 ) )
            break;

        fputs( buffer, hlp );
    }
}

/*-------------------------------------------------------------------------*
 *  "append_index" generates text for an index which is appended to the 
 *  help data file
 *
 *  returns:  nothing
 */
void append_index( FILE *hlp )                  // output file
{
    int i;

    fprintf( hlp, "#INDEX$\n" );
    fprintf( hlp, "Topic index\n\n" );

    for( i = 0; i < Topic; i++ )
    {
        if( strcmp( "INDEX", Topic_list[i].name ) )
        {
            fprintf( hlp, 
                     "    @%s$\n", 
                     Topic_list[i].name );
        }
    }
}

/*-------------------------------------------------------------------------*
 *  "main" make help entry point
 *
 *  returns:  non-zero on error
 */
int main( int argc, char *argv[] )
{
    FILE *txt, *hlp;
    long length;

    if( argc == 3 )
    {
        txt = fopen( argv[1], "r" );

        if( !txt )
        {
            printf( "could not open input file -%s-\n", argv[1] );
            exit( 1 );
        }

        hlp = fopen( argv[2], "w" );

        if( !txt )
        {
            printf( "could not open output file -%s-\n", argv[2] );
            exit( 1 );
        }
    }
    else
    {
        printf( "usage: makehelp <input file> <output file>\n" );
        exit( 1 );
    }

    length = create_topic_table( txt );
    verify_jumps( txt );
    traverse( Topic_table );
    make_jump_table( hlp, length );
    append_topic_text( hlp, txt );
    append_index( hlp );

    fclose( txt );
    fclose( hlp );
}

| home | contents | previous | next page | send comment | send link | add bookmark |

Copyright © 2004, Stephen R. Schmitt